CtrlK
BlogDocsLog inGet started
Tessl Logo

plugin-architecture-patterns

Plugin architecture, registration, and trait patterns

54

Quality

61%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./.ai-rulez/skills/plugin-architecture-patterns/SKILL.md
SKILL.md
Quality
Evals
Security

Plugin Architecture & Registration

Plugin Types

TypeTraitLocation
Document ExtractorDocumentExtractor: Pluginplugins/extractor/trait.rs
OCR BackendOcrBackend: Pluginplugins/ocr/trait.rs
Post ProcessorPostProcessor: Pluginplugins/processor/trait.rs
ValidatorValidator: Pluginplugins/validator/trait.rs

DocumentExtractor Implementation

use crate::plugins::{DocumentExtractor, Plugin};
use async_trait::async_trait;

pub struct MyExtractor;

impl Plugin for MyExtractor {
    fn name(&self) -> &str { "my-extractor" }
    fn version(&self) -> String { env!("CARGO_PKG_VERSION").to_string() }
}

#[async_trait]
impl DocumentExtractor for MyExtractor {
    async fn extract(&self, input: ExtractInput, config: &ExtractionConfig)
        -> Result<ExtractedDocument> { /* ... */ }

    fn supported_mime_types(&self) -> &[&str] { &["application/x-custom"] }
    fn priority(&self) -> i32 { 50 }

    // WASM support (optional)
    fn as_sync_extractor(&self) -> Option<&dyn SyncExtractor> { None }
}

Priority System

RangeUse
0-25Fallback/low-quality
26-49Alternative extractors
50Default (built-in)
51-75Premium/enhanced
76-100Specialized/high-priority

Registry selects highest priority extractor for each MIME type. Override built-ins with priority > 50.

Registration

// In extractors/mod.rs → register_default_extractors()
let registry = get_document_extractor_registry();
let mut registry = registry.write()
    .map_err(|e| XbergError::Other(format!("Registry lock poisoned: {}", e)))?;
registry.register(Arc::new(MyExtractor::new()))?;

Feature-Gated Registration

#[cfg(feature = "office")]
{
    registry.register(Arc::new(DocxExtractor::new()))?;
    registry.register(Arc::new(PptxExtractor::new()))?;
}

PostProcessor Pattern

impl PostProcessor for MyProcessor {
    async fn process(&self, result: &mut ExtractionResult, config: &ExtractionConfig)
        -> Result<()> {
        result.content = process_content(&result.content);
        Ok(())
    }
    fn stage(&self) -> ProcessorStage { ProcessorStage::Middle }
}

Stages: EarlyMiddleLate. Failures isolated (don't block others).

Critical Rules

  1. All plugins MUST be Send + Sync
  2. Feature gate with #[cfg(feature = "...")] for optional formats
  3. Use #[async_trait] for DocumentExtractor
  4. Initialization via ensure_initialized() (lazy, called before first extraction)
  5. Plugin names: kebab-case (e.g., "pdf-extractor")
Repository
xberg-io/xberg
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.