Skip to content

Latest commit

 

History

History
138 lines (108 loc) · 4.41 KB

File metadata and controls

138 lines (108 loc) · 4.41 KB

Plugin Development

Plugins let applications observe or transform CortexDB lifecycle operations without forking the core library.

Define a plugin

Use defineCortexPlugin() to validate hook names and preserve exact TypeScript types.

import { Cortex, defineCortexPlugin } from "cortexdb"

const plugin = defineCortexPlugin({
  name: "tag-docs-memories",
  version: "1.0.0",
  priority: 10,
  hooks: {
    beforeRemember: (context) => ({
      ...context.input,
      tags: [...(context.input.tags ?? []), "docs"],
    }),
    afterRemember: (context) => {
      console.log(`stored ${context.record.id}`)
    },
  },
})

const db = await Cortex.memory({ plugins: [plugin] })

Hook order and errors

Plugins execute by descending priority, then registration order. Hook errors are isolated: the registry records a PluginErrorEvent, notifies error listeners, and allows the host operation to continue.

const unsubscribe = db.plugins.onError((event) => {
  console.error(event.pluginName, event.hook, event.message)
})

console.log(db.plugins.errors())
db.plugins.clearErrors()
unsubscribe()

Registry API

Method Description
register(plugin) Adds a plugin. Duplicate names are rejected.
unregister(pluginOrName) Removes a plugin by name or object; returns true when removed.
list() Returns registered plugins in execution order.
errors() Returns captured plugin hook errors.
clearErrors() Clears captured hook errors.
onError(listener) Subscribes to hook errors and returns an unsubscribe function.

Hook names

Hook Can transform? Runs when
beforeRemember Yes Before a memory is normalized and stored.
afterRemember Yes After a memory is stored.
beforeRecall Yes Before memory recall.
afterRecall Yes After recall results are produced.
beforePack Yes Legacy alias before context packing.
afterPack Yes Legacy alias after context packing.
beforeContextPack Yes Before context packing.
afterContextPack Yes After context packing.
beforeSearch Yes Before semantic/text/hybrid/graph/temporal search.
afterSearch Yes After search results.
onRecordWrite No After storage set or batch set writes a valid Cortex record.
onRiskDetected No After security scan/find detects risks.
onCompaction No After db.compact() succeeds.

Recall rewriting example

db.plugins.register(defineCortexPlugin({
  name: "recall-rewriter",
  hooks: {
    beforeRecall: (context) => ({
      ...(typeof context.input === "string" ? {} : context.input),
      query: "normalized project vocabulary",
    }),
    afterRecall: (context) => context.results.slice(0, 5),
  },
}))

Search observer example

db.plugins.register(defineCortexPlugin({
  name: "search-audit",
  hooks: {
    beforeSearch: (context) => {
      console.log(`search mode=${context.mode}`)
    },
    afterSearch: (context) => {
      console.log(`results=${context.results.length}`)
    },
  },
}))

Context redaction example

The built-in example plugin redacts secrets and PII-like text from packed context output.

import { createContextRedactionPlugin } from "cortexdb"

db.plugins.register(createContextRedactionPlugin({ marker: "[MASKED]" }))

Operation logger example

createOperationLoggerPlugin() appends lifecycle events to an array.

import { createOperationLoggerPlugin, type OperationLogEntry } from "cortexdb"

const log: OperationLogEntry[] = []
db.plugins.register(createOperationLoggerPlugin(log))
await db.remember({ content: "Log this memory" })
console.log(log)

Record write observer

withPluginRecordWriteObserver(storage, plugins) wraps a storage adapter so onRecordWrite hooks observe successful set writes that decode to valid Cortex records. Cortex applies this wrapper automatically to its configured storage.

Guidelines

  • Keep hooks deterministic and fast; hooks run inline with user operations.
  • Treat hook context as user-controlled input unless it came from a trusted source.
  • Return transformed values only when you intentionally want to replace the input/result.
  • Do not throw for routine filtering; return a transformed value instead.
  • Use unique plugin names and semantic versions.
  • Prefer onRiskDetected and onRecordWrite for audit logging instead of duplicating storage writes in transform hooks.