Install any skill in seconds. Free to start, no credit card required.
Get Started Free →MIME type detection and extractor routing in core/mime.rs and core/extractor/bytes.rs — the extension→EXT_TO_MIME→validate→registry→extractor flow, key detection functions, the 115 case-insensitive extension map, priority-based registry selection, wildcard MIME families, and how to add a new MIME type. Load when adding a format, wiring an extractor to a MIME type, or debugging why a file routes to the wrong (or no) extractor.
.claude/skills/xberg-io-mime-detection-routing/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✗→✓ | ▲ Improved | -15% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 7% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -21% | 0% |
| case-03 | ✗→✓ | ▲ Improved | -17% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -7% | 0% |
textPolicy -> content and/or extension evidence -> validate_mime_type -> registry.get(mime) -> extractor
| Function | Location | Behaviour | | --- | --- | --- | | detect_mime_type(path, check_exists: bool) | core/mime.rs | Path-based only — never reads bytes. Lowercased extension → EXT_TO_MIME, then tree-sitter extension detection (feature tree-sitter), then mime_guess::from_path. check_exists gates a file-existence check, not content inspection. | | detect_mime_type_from_bytes(bytes) | core/mime.rs | Magic-number detection via the infer crate. The only content-sniffing entry point. | | validate_mime_type(mime) | core/mime.rs | Parses the media type, matches its case-insensitive essence against SUPPORTED_MIME_TYPES, and returns the registered MIME spelling. Parameters such as charset do not affect extractor routing. It does not consult the extractor registry. |
FORMATS: &[FormatEntry { extensions, mime_type, aliases }] in core/mime.rs. EXT_TO_MIME and SUPPORTED_MIME_TYPES are LazyLocks derived from it by iteration — there is no m.insert call site to add to, and hand-editing either is impossible.
The full registry publishes 106 formats, 140 unique extensions, and 53 aliases, verified by scripts/sync_supported_counts.py verify. The published count constants describe that static registry; runtime availability is its intersection with registered extractors. Extension lookup is case-insensitive (the extension is lowercased before the map hit).
rustlet registry = get_document_extractor_registry(); // plugins/registry/mod.rs let guard = registry.read()?; let extractor: Arc<dyn DocumentExtractor> = guard.get(mime_type)?; // Result, not Option
DocumentExtractorRegistry::get (plugins/registry/extractor.rs) returns the highest-priority() extractor for the MIME type, and returns Err — not None — when none matches.
An extractor may register a family: "image/*" matches image/png, image/jpeg, and so on (prefix match on a registered type ending in /*).
FormatEntry to FORMATS in crates/xberg/src/core/mime.rs. EXT_TO_MIME andSUPPORTED_MIME_TYPES update automatically.
scripts/sync_supported_counts.py sync to update published count claims, then run itsverify command.
InternalDocumentExtractor (not DocumentExtractor — seeplugin-architecture-patterns) with supported_mime_types() returning the MIME.
crates/xberg/src/extractors/mod.rs::register_default_extractors().validate_mime_type() before extraction — but do not treat it as proof an extractor exists.detect_mime_type inspects no content. Extraction defaults to PreferContent, which performsbounded content inspection and falls back to a supported extension. Use ContentOnly when the filename must be ignored; use TrustExtension only for trusted sources.
application/octet-stream is the exception: itis a generic placeholder and triggers policy-based detection.
EXT_TO_MIME or SUPPORTED_MIME_TYPES — edit FORMATS.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-16 | fail→pass | 21,188 | 7,818 | -63% | 1 | 1 | 0% | 2,935 | 2,493 | -15% | 0 | 0 | — |
case-01 | fail→pass | 16,174 | 17,199 | +6% | 1 | 1 | 0% | 3,187 | 3,397 | +7% | 0 | 0 | — |
case-02 | fail→pass | 27,569 | 21,338 | -23% | 1 | 1 | 0% | 4,282 | 3,383 | -21% | 0 | 0 | — |
case-03 | fail→pass | 15,995 | 14,609 | -9% | 1 | 1 | 0% | 3,314 | 2,748 | -17% | 0 | 0 | — |
case-04 | fail→pass | 13,698 | 6,431 | -53% | 1 | 1 | 0% | 2,457 | 2,275 | -7% | 0 | 0 | — |
case-05 | fail→pass | 16,741 | 11,558 | -31% | 1 | 1 | 0% | 1,829 | 2,184 | +19% | 0 | 0 | — |
case-15 | fail→pass | 37,906 | 7,697 | -80% | 1 | 1 | 0% | 7,102 | 1,325 | -81% | 0 | 0 | — |
case-06 | fail→pass | 18,820 | 5,832 | -69% | 1 | 1 | 0% | 2,494 | 1,816 | -27% | 0 | 0 | — |
case-07 | fail→pass | 14,778 | 7,371 | -50% | 1 | 1 | 0% | 1,678 | 2,206 | +31% | 0 | 0 | — |
case-08 | pass→pass | 15,580 | 7,472 | -52% | 1 | 1 | 0% | 1,758 | 1,327 | -25% | 0 | 0 | — |
case-09 | fail→pass | 20,492 | 8,434 | -59% | 1 | 1 | 0% | 2,610 | 1,463 | -44% | 0 | 0 | — |
case-10 | fail→pass | 25,224 | 8,028 | -68% | 1 | 1 | 0% | 1,613 | 1,376 | -15% | 0 | 0 | — |
case-11 | fail→pass | 10,380 | 9,028 | -13% | 1 | 1 | 0% | 1,627 | 1,558 | -4% | 0 | 0 | — |
case-12 | pass→pass | 8,474 | 8,907 | +5% | 1 | 1 | 0% | 1,723 | 1,666 | -3% | 0 | 0 | — |
case-13 | fail→pass | 19,207 | 8,815 | -54% | 1 | 1 | 0% | 2,503 | 1,610 | -36% | 0 | 0 | — |
case-14 | pass→pass | 11,826 | 9,736 | -18% | 1 | 1 | 0% | 1,925 | 1,755 | -9% | 0 | 0 | — |
case-17 | fail→pass | 22,497 | 2,761 | -88% | 1 | 1 | 0% | 3,161 | 1,355 | -57% | 0 | 0 | — |
case-18 | pass→pass | 19,274 | 9,530 | -51% | 1 | 1 | 0% | 1,900 | 1,501 | -21% | 0 | 0 | — |
case-19 | fail→pass | 17,376 | 12,801 | -26% | 1 | 1 | 0% | 2,077 | 2,072 | -0% | 0 | 0 | — |
case-20 | pass→pass | 21,371 | 19,373 | -9% | 1 | 1 | 0% | 3,209 | 3,654 | +14% | 0 | 0 | — |
case-21 | pass→pass | 23,102 | 16,243 | -30% | 1 | 1 | 0% | 2,982 | 3,837 | +29% | 0 | 0 | — |
case-22 | pass→pass | 22,632 | 19,819 | -12% | 1 | 1 | 0% | 3,199 | 3,686 | +15% | 0 | 0 | — |
case-23 | fail→pass | 21,342 | 7,491 | -65% | 1 | 1 | 0% | 2,740 | 1,297 | -53% | 0 | 0 | — |
case-24 | fail→pass | 23,966 | 10,890 | -55% | 1 | 1 | 0% | 3,254 | 1,971 | -39% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +71 percentage points is the difference between those two pass rates over the 24 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/24/2026 | +59% |
| gemini-3.6-flash | verified | 8/11/2026 | +41% |
Other measured skills in the registry, with their headline benchmark lift.