Fuse
Internals & ExtendingExtending

Adding a Template

How to define the default file extensions and exclusions Fuse applies to a project type.

A template tells Fuse which files to consider for a kind of project before any reduction or scoping happens. It names the file extensions to include and the directories and patterns to exclude, so that a fusion of, say, a Go project does not waste effort on a vendored dependency tree or build output. A template carries no reduction logic of its own; it shapes the candidate set the collection stage produces.

This page is written for an engineer adding discovery defaults for a project type Fuse does not yet recognize.

Implementation Context

A template implements IProjectTemplate, which declares four members: a Name, the Extensions to include, the ExcludeDirectories to skip, and the ExcludePatterns to skip. Most templates extend ProjectTemplateBase, which leaves Name, Extensions, and ExcludeDirectories abstract and supplies an empty ExcludePatterns by default, so a template that excludes no glob patterns need not declare that member.

Templates are discovered through dependency injection. At startup the template registry collects every registered IProjectTemplate and keys each one by its Name, which must match a value of the project template enumeration exactly. Resolution is by that enumeration value, and an unknown request falls back to the generic template. Existing templates live in the Fuse.Collection project under its templates directory and are worth reading as models.

Define The Template Class

The following template describes a project type whose sources end in .mylang, with two build directories and one generated-file pattern to exclude. Extensions and directory names carry their natural form; extensions include the leading dot.

using Fuse.Collection.Models;

namespace Fuse.Collection.Templates.Definitions;

/// <summary>
///     Template for MyLang projects.
/// </summary>
public sealed class MyLangTemplate : ProjectTemplateBase
{
    /// <inheritdoc />
    public override string Name => nameof(ProjectTemplate.MyLang);

    /// <inheritdoc />
    public override IReadOnlyCollection<string> Extensions =>
        [".mylang", ".mylproj"];

    /// <inheritdoc />
    public override IReadOnlyCollection<string> ExcludeDirectories =>
        ["build", "dist", ".git"];

    /// <inheritdoc />
    public override IReadOnlyCollection<string> ExcludePatterns =>
        ["*.generated.mylang"];
}

The Name returns the enumeration member by way of nameof, which keeps the string and the enumeration value from drifting apart. Add the corresponding member to the project template enumeration so the name has a value to resolve against.

Registration

A template becomes available once it is registered as a singleton IProjectTemplate where the host composes its services, next to the other template registrations. The registry picks it up automatically from the set of registered templates; no further wiring is needed.

services.AddSingleton<IProjectTemplate, MyLangTemplate>();

After registration the template is selectable by name. At the terminal it is the value of the template option on the generic command, and over the Model Context Protocol it is the template argument of the fuse_generic tool. In both cases the name is the enumeration member you defined.

What This Does Not Cover

This page covers only discovery defaults. A template does not reduce or analyze the files it admits; those files pass through with whitespace normalization unless a capability is registered for their extensions. To add that behavior, see Adding a Language Plugin for source languages and Adding a Format Reducer for markup and configuration formats.

Next

The Templates reference lists the built-in templates and their extensions. The contributing guide covers coding standards and the pull request checklist.

On this page