Writing plugins

Plugins keep provider and framework dependencies outside the core package. Public protocols cover Source, Ranker, Policy, Renderer, and PythonTokenizer.

Ranker

import cognoxium as cx

class KeywordRanker:
    fingerprint = "keyword-v1"

    def score_batch(self, query, items):
        query = query.casefold()
        return [float(query in item.payload.text_value().casefold()) for item in items]

frame = cx.CognitionFrame.from_records([
    {"id": "a", "payload": "release ready"},
    {"id": "b", "payload": "work in progress"},
])
ranked = frame.rank("release", ranker=KeywordRanker())
print(ranked.explain())
Scan[context records] -> Rank[keyword-v1]

A ranker must return one numeric score per item. Invalid lengths or non-numeric results raise PluginError.

Policy

class RejectUntrustedExternally:
    id = "example.reject-untrusted.v1"

    def evaluate(self, item, boundary):
        if boundary.kind == "external" and item.trust is cx.Trust.UNTRUSTED:
            return "untrusted_source"
        return None

pack = frame.pack(
    budget=100,
    boundary=cx.Boundary.external("provider"),
    policies=[RejectUntrustedExternally()],
)

A policy is called once per item and returns a stable reason code or None. Avoid network calls in this per-item method; authenticate and enrich records before packing.

Source

Source.load() returns an iterable of record mappings. See the complete StaticSource example in Building a CognitionFrame. The Source ID identifies the adapter; each returned item still needs a meaningful sources field.

Renderer

class IdRenderer:
    id = "ids-v1"

    def render(self, pack):
        return [item.id for item in pack.items]

ids = pack.render(IdRenderer())

A renderer receives an immutable ContextPack. It must reject unsupported payloads instead of silently stringifying them.

Python tokenizer fallback

class WordTokenizer:
    fingerprint = "words-v1"
    thread_safe = True

    def count_batch(self, values):
        return [len(value.split()) for value in values]

profile = cx.profiles.huggingface(
    WordTokenizer(),
    profile_id="example:words-v1",
)

The first use emits PerformanceWarning because Python tokenization is a slower fallback. count_batch() must return one non-negative integer per value.

Reproducibility contract

Plugins must be deterministic for a stable fingerprint. Change the fingerprint whenever code, vocabulary, model, configuration, envelope accounting, or remote service version can change results. Cognoxium cannot validate that a fingerprint truthfully identifies external state.