Fuse
Internals & Extending

Capability and Plugin Model

How Fuse keeps language behavior in plugins and resolves it by file extension through capability registries.

Fuse has two extension-driven seams. Reduction and presentation use capability interfaces from the plugin abstractions. Persistent syntax indexing uses ILanguageSyntaxProvider to extract language-tagged symbols and chunks. Typed semantic analysis is separate and remains C#-only.

This page is for engineers who want to understand the plugin boundary and for contributors adding support for a new language or format.

Architectural Rationale

Extension registries keep reducer selection and syntax extraction out of per-file switch statements. A registered capability claims extensions, and later registrations win a conflict. This does not make every tier language-neutral: compiler-backed graph construction, verification, and refactoring use the C# Roslyn path.

Index Language Tiers

The persistent index selects a syntax provider by extension:

ProviderExtensionsOutput
C#.csRoslyn-syntax symbols and chunks tagged csharp
Python.pyBounded lexical class/function symbols and chunks tagged python
JavaScript.js, .jsx, .mjs, .cjs, .ts, .tsx, .mts, .ctsBounded lexical class/function symbols and chunks tagged javascript

These records support exact lookup, full-text search, and task localization through language-agnostic tables. Python and JavaScript do not produce typed edges, compiler signatures, route or dependency wiring, build-capture verification, or compiler-executed refactors.

The maintained Python and JavaScript providers are frozen at their current syntax scope. A first-party semantic provider for another language requires that language's real compiler service, not another parser or regex layer.

Registration through Dependency Injection

Language behavior is registered with the service container, not hard-coded. The default composition registers the C# language plugin and the built-in format reducers:

services.AddCSharpLanguage();   // C# reducer, skeleton, markers, dependencies, type locator, maps, detectors
services.AddFormatReducers();   // reducers for HTML, JSON, YAML, XML, and other formats

A host that wants a different set of languages calls the core registration directly and composes its own plugins on top.

The Capability Contracts

Every capability extends the base contract, which declares the file extensions it handles. Resolution is by extension, matched case-insensitively, each including its leading dot.

InterfaceResponsibility
IContentReducerReduce a file's content for its extension
ISkeletonExtractorProduce a signatures-only structural skeleton
ISemanticMarkerGeneratorGenerate type-level annotation comments
IDependencyExtractorExtract referenced type names for the dependency graph
ITypeNameLocatorResolve a type name to the file or files that define it
ISymbolOutlineExtractorProduce a per-file symbol outline for the workspace map
ISymbolSliceExtractorReduce a file to one member, keeping its body and signatures only for the rest
IRouteMapGeneratorProduce an endpoint table for the workspace map
IProjectGraphGeneratorProduce a solution and project reference graph
IPatternDetectorDetect a cross-codebase convention across the indexed files

ISymbolOutlineExtractor and ISymbolSliceExtractor live in Fuse.Plugins.Abstractions alongside the other contracts. The outline extractor backs the table-of-contents survey; the slice extractor backs Type.Member focus scoping.

Pattern detectors are the exception to per-extension resolution. They derive from a batch base class that runs a reset, one accumulate call per file, and a finalize call, so a detector folds signals across the whole fused set in a single pass rather than being resolved for one file. Detectors are stateful and run one batch at a time.

Capability Registries

A capability registry builds an extension-to-capability map at startup. It iterates every registered implementation, and for each extension that implementation declares, it records the implementation under that extension. The pipeline then resolves a capability by passing a file's extension; the registry returns the registered implementation or nothing when no capability handles that extension.

Last registration wins. When two implementations declare the same extension, the one registered later replaces the earlier one in the map. A specialized plugin can therefore override a default by registering after it. Resolution returning nothing is a normal outcome: a file whose extension has no registered reducer passes through reduction unchanged, and a file with no registered dependency extractor contributes an empty reference list to the graph.

C# reduction capabilities follow this rule in the default host. The C# language plugin registers the content reducer, project-graph generator, and pattern detectors. The Roslyn plugin supplies structural C# extractors. The separate persistent syntax index selects ILanguageSyntaxProvider implementations and stores a language tag per file.

Loading diagram...

The Five Registries

The core registration builds five registries, one per resolvable-by-extension capability that the pipeline consults during collection-to-reduction work:

  • IContentReducer
  • ISkeletonExtractor
  • ISemanticMarkerGenerator
  • IDependencyExtractor
  • ITypeNameLocator

The remaining reduction capabilities (route map and project graph generators) are resolved as single optional services, and pattern detectors run as a batch. These registries do not define the typed semantic tier.

What This Does Not Cover

This page describes the capability boundary and resolution. It does not document the internal algorithms of any specific capability, such as how the dependency extractor or the full-text index work; see Retrieval internals. It does not give a step-by-step plugin walkthrough.

Next

See Extending Fuse With A Language Plugin to implement and register a new language. See The Fusion Pipeline for where each capability is consulted, and Core Concepts for the conceptual overview.

On this page