# How to Create Custom Prompt Plugins for OpenDeepWiki AI Code Analysis

> Learn to create custom prompt plugins for OpenDeepWiki AI code analysis by implementing the IPromptPlugin interface and registering your custom solution. Enhance your code analysis today.

- Repository: [AIDotNet/OpenDeepWiki](https://github.com/aidotnet/opendeepwiki)
- Tags: how-to-guide
- Published: 2026-02-16

---

**To create custom prompt plugins for OpenDeepWiki AI code analysis, implement the `IPromptPlugin` interface and register your implementation in the dependency injection container to replace the default `FilePromptPlugin`.**

OpenDeepWiki is an open-source AI-powered code analysis tool that generates documentation by feeding source code into Large Language Models (LLMs). The system uses a pluggable prompt architecture that allows developers to create custom prompt plugins for OpenDeepWiki AI code analysis, enabling prompts to be loaded from databases, APIs, or embedded resources instead of the default file system.

## Understanding the IPromptPlugin Interface

### Core Interface Definition

The prompt plugin system centers on a single abstraction located at [`src/OpenDeepWiki/Services/Prompts/IPromptPlugin.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Services/Prompts/IPromptPlugin.cs). This interface defines the contract for loading and processing prompt templates:

```csharp
public interface IPromptPlugin
{
    Task<string> LoadPromptAsync(
        string promptName,
        Dictionary<string, string>? variables = null,
        CancellationToken ct = default);
}

```

The `LoadPromptAsync` method accepts a `promptName` (typically corresponding to a template identifier), an optional dictionary of variables for placeholder substitution, and a cancellation token. It returns the processed prompt string ready for LLM consumption.

### Default File-Based Implementation

OpenDeepWiki ships with `FilePromptPlugin` located at [`src/OpenDeepWiki/Services/Prompts/FilePromptPlugin.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Services/Prompts/FilePromptPlugin.cs). This default implementation:

- Reads prompt templates from a configurable directory on disk
- Expects templates to use `{{variableName}}` syntax for placeholders
- Uses the static method `FilePromptPlugin.SubstituteVariables` to perform regex-based replacement

The default registration occurs in [`src/OpenDeepWiki/Program.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Program.cs) (lines 266-277), where the plugin is configured to read from a `Prompts` subdirectory of the application root.

## Implementing Custom Prompt Plugins

### Database-Driven Prompt Plugin

For scenarios requiring dynamic prompt management or multi-tenant configurations, implement a database-backed plugin. This example assumes an Entity Framework `PromptDbContext` with a `Prompts` table:

```csharp
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using OpenDeepWiki.Services.Prompts;

public class DbPromptPlugin : IPromptPlugin
{
    private readonly PromptDbContext _db;

    public DbPromptPlugin(PromptDbContext db) => _db = db;

    public async Task<string> LoadPromptAsync(
        string promptName,
        Dictionary<string, string>? variables = null,
        CancellationToken ct = default)
    {
        var entity = await _db.Prompts.FindAsync(
            new object[] { promptName }, 
            ct);
            
        if (entity == null)
            throw new FileNotFoundException(
                $"Prompt \"{promptName}\" not found in DB.");

        var template = entity.Content;
        
        return variables == null || variables.Count == 0
            ? template
            : FilePromptPlugin.SubstituteVariables(template, variables);
    }
}

```

This implementation maintains consistency with the default behavior by reusing `FilePromptPlugin.SubstituteVariables` for placeholder replacement, ensuring `{{variable}}` syntax works identically across storage backends.

### In-Memory Hardcoded Plugin

For testing scenarios or lightweight deployments where prompts rarely change, embed templates directly in code:

```csharp
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using OpenDeepWiki.Services.Prompts;

public class InMemoryPromptPlugin : IPromptPlugin
{
    private static readonly IReadOnlyDictionary<string, string> Templates =
        new Dictionary<string, string>
        {
            ["Summarize"] = "You are a concise summarizer. Summarize the following text:\n{{content}}",
            ["CodeReview"] = "You are a code reviewer. Analyze the code and give suggestions:\n{{code}}"
        };

    public Task<string> LoadPromptAsync(
        string promptName,
        Dictionary<string, string>? variables = null,
        CancellationToken ct = default)
    {
        if (!Templates.TryGetValue(promptName, out var tmpl))
            throw new FileNotFoundException(
                $"Prompt \"{promptName}\" not defined.");

        var result = variables == null || variables.Count == 0
            ? tmpl
            : FilePromptPlugin.SubstituteVariables(tmpl, variables);

        return Task.FromResult(result);
    }
}

```

This approach eliminates external dependencies and ensures prompts are version-controlled alongside application code.

## Registering Your Plugin in the DI Container

To activate your custom implementation, replace the default registration in [`src/OpenDeepWiki/Program.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Program.cs). The original registration (lines 266-277) configures `FilePromptPlugin` like this:

```csharp
builder.Services.AddSingleton<IPromptPlugin>(sp =>
{
    var env = sp.GetRequiredService<IHostEnvironment>();
    var promptsDir = Path.Combine(env.ContentRootPath, "Prompts");
    return new FilePromptPlugin(promptsDir);
});

```

Replace this with your custom implementation. For the in-memory plugin:

```csharp
builder.Services.AddSingleton<IPromptPlugin, InMemoryPromptPlugin>();

```

For the database plugin (assuming `PromptDbContext` is already registered):

```csharp
builder.Services.AddScoped<IPromptPlugin, DbPromptPlugin>();

```

The service lifetime should match your storage backend: singleton for in-memory or file-based, scoped for database contexts that should align with request lifecycles.

## How WikiGenerator Uses Your Plugin

The `WikiGenerator` class located at [`src/OpenDeepWiki/Services/Wiki/WikiGenerator.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Services/Wiki/WikiGenerator.cs) (lines 68-84) consumes the prompt plugin during the documentation generation pipeline:

```csharp
public class WikiGenerator : IWikiGenerator
{
    private readonly IPromptPlugin _promptPlugin;
    // ... other dependencies injected

    private async Task<string> BuildPromptAsync(
        string promptName, 
        Dictionary<string, string> variables, 
        CancellationToken ct)
    {
        var prompt = await _promptPlugin.LoadPromptAsync(
            promptName, 
            variables, 
            ct);
        // prompt is then sent to the configured LLM backend
        return prompt;
    }
}

```

Because `WikiGenerator` depends on the abstraction `IPromptPlugin` rather than concrete implementations, your custom plugin integrates seamlessly without modifying the core generation logic. The system resolves the registered implementation at runtime, whether it loads from disk, database, or memory.

## Summary

- **Implement `IPromptPlugin`**: Create a class implementing the single-method interface located at [`src/OpenDeepWiki/Services/Prompts/IPromptPlugin.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Services/Prompts/IPromptPlugin.cs) to define how prompt templates are retrieved and processed.
- **Reuse variable substitution**: Leverage `FilePromptPlugin.SubstituteVariables` to maintain consistent `{{variable}}` placeholder replacement across custom storage backends.
- **Register in DI**: Replace the default `FilePromptPlugin` registration in [`src/OpenDeepWiki/Program.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Program.cs) (lines 266-277) with your implementation using `AddSingleton` or `AddScoped` depending on your storage requirements.
- **Zero core changes**: `WikiGenerator` automatically uses your plugin through constructor injection of `IPromptPlugin`, requiring no modifications to the AI analysis pipeline.

## Frequently Asked Questions

### What is the default prompt plugin in OpenDeepWiki?

OpenDeepWiki uses `FilePromptPlugin` as the default implementation, located at [`src/OpenDeepWiki/Services/Prompts/FilePromptPlugin.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Services/Prompts/FilePromptPlugin.cs). This plugin reads prompt templates from a configurable directory on disk, expects Markdown files, and performs variable substitution using the `{{variableName}}` syntax.

### Can I use multiple prompt plugins simultaneously?

The current architecture in [`src/OpenDeepWiki/Program.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Program.cs) registers a single `IPromptPlugin` implementation in the dependency injection container. To use multiple sources simultaneously, you would need to create a composite plugin that implements `IPromptPlugin` and internally delegates to multiple backends (file, database, memory) based on prompt naming conventions or fallback logic.

### How do I handle variable substitution in custom plugins?

Custom plugins should support the same `{{variable}}` placeholder syntax as the default implementation to ensure compatibility with existing templates. You can reuse the static helper method `FilePromptPlugin.SubstituteVariables(string template, Dictionary<string, string> variables)` located in [`src/OpenDeepWiki/Services/Prompts/FilePromptPlugin.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Services/Prompts/FilePromptPlugin.cs), or implement your own regex-based replacement using the pattern `\{\{(\w+)\}\}`.

### Where should I register my custom prompt plugin?

Register your custom implementation in [`src/OpenDeepWiki/Program.cs`](https://github.com/AIDotNet/OpenDeepWiki/blob/main/src/OpenDeepWiki/Program.cs) by replacing the default registration found at lines 266-277. Use `builder.Services.AddSingleton<IPromptPlugin, YourCustomPlugin>()` for stateless or file-based implementations, or `builder.Services.AddScoped<IPromptPlugin, YourDbPlugin>()` if your plugin depends on database contexts that should align with HTTP request lifecycles.