Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Plugin architecture, registration, and trait patterns
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | -24% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -13% | 0% |
| case-03 | ✗→✓ | ▲ Improved | -24% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -29% | 0% |
| case-06 | ✗→✓ | ▲ Improved | -17% | 0% |
| Type | Trait | Location | | ------------------ | --------------------------- | ---------------------------- | | Document Extractor | DocumentExtractor: Plugin | plugins/extractor/trait.rs | | OCR Backend | OcrBackend: Plugin | plugins/ocr/trait.rs | | Post Processor | PostProcessor: Plugin | plugins/processor/trait.rs | | Validator | Validator: Plugin | plugins/validator/trait.rs |
rustuse 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 } }
| Range | Use | | ------ | ------------------------- | | 0-25 | Fallback/low-quality | | 26-49 | Alternative extractors | | 50 | Default (built-in) | | 51-75 | Premium/enhanced | | 76-100 | Specialized/high-priority |
Registry selects highest priority extractor for each MIME type. Override built-ins with priority > 50.
rust// 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()))?;
rust#[cfg(feature = "office")] { registry.register(Arc::new(DocxExtractor::new()))?; registry.register(Arc::new(PptxExtractor::new()))?; }
rustimpl 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: Early → Middle → Late. Failures isolated (don't block others).
Send + Sync#[cfg(feature = "...")] for optional formats#[async_trait] for DocumentExtractorensure_initialized() (lazy, called before first extraction)"pdf-extractor")Other measured skills in the registry, with their headline benchmark lift.