How to Add a Custom Summary Template or Workflow to Meetily's Summary Engine

Meetily supports custom summary templates through a JSON-based registry system that automatically loads user-defined templates from a designated directory, requiring no code changes for basic customization.

Meetily's meeting summarization pipeline is built for extensibility. Whether you need a daily standup format, project retrospectives, or industry-specific output structures, you can inject custom templates without modifying core source code. This guide walks through adding a custom summary template or workflow to Meetily's Rust-based summary engine, using the actual implementation in Zackriya-Solutions/meetily.

Meetily's Summary Pipeline Architecture

The summary engine consists of five coordinated components:

Component Role Key Source File
Template Registry Stores built-in templates (daily standup, standard meeting) frontend/src-tauri/src/summary/templates/defaults.rs
Template Loader Scans user templates directory and merges with built-ins frontend/src-tauri/src/summary/templates/loader.rs
Command Bridge Tauri commands exposing templates to the frontend frontend/src-tauri/src/summary/template_commands.rs
Processor Injects transcript into template and calls LLM frontend/src-tauri/src/summary/processor.rs
Service Layer Orchestrates end-to-end summary generation frontend/src-tauri/src/summary/service.rs

Creating a Custom Summary Template

Step 1: Define Your Template JSON

Create a JSON file following Meetily's template schema. The file supports title interpolation (e.g., {{date}}) and section-based LLM prompts.

{
  "title": "Project Sync – {{date}}",
  "sections": [
    {
      "heading": "Highlights",
      "prompt": "Summarize the most important points discussed."
    },
    {
      "heading": "Action Items",
      "prompt": "List any tasks that were assigned with owners."
    },
    {
      "heading": "Blockers",
      "prompt": "Identify any obstacles mentioned that need escalation."
    }
  ]
}

Save this file as frontend/src-tauri/src/summary/templates/custom/my_custom_template.json. The loader.rs implementation recurses subdirectories, so you can organize templates into folders.

Step 2: Register the Template (Automatic Loading)

The loader.rs implementation handles registration automatically. No code changes are required:

// Simplified excerpt from loader.rs
pub fn load_all_templates() -> Vec<(&'static str, &'static str)> {
    let mut templates = defaults::get_builtin_templates();
    
    // Scan user-provided directory
    if let Ok(entries) = std::fs::read_dir(custom_template_dir()) {
        for entry in entries.flatten() {
            if let Ok(content) = std::fs::read_to_string(entry.path()) {
                if let Some(id) = entry.path().file_stem().and_then(|s| s.to_str()) {
                    templates.push((id, Box::leak(content.into_boxed_str())));
                }
            }
        }
    }
    templates
}

The template ID is derived from the filename (without extension). In this example: my_custom_template.

Action required: Restart the application or trigger hot-reload for the loader to pick up new files.

Exposing Templates to the Frontend

Listing Available Templates

The frontend retrieves templates through Tauri commands defined in template_commands.rs:

import { invoke } from '@tauri-apps/api/tauri';

async function loadSummaryTemplates() {
  const templates = await invoke<{ id: string; name: string }[]>(
    'list_summary_templates'
  );
  
  // Returns: [{ id: 'daily_standup', name: 'Daily Standup' }, ...]
  return templates;
}

Generating a Summary with Your Template

Pass the templateId when invoking summary generation:

await invoke('generate_summary', {
  meetingId: currentMeeting.id,
  templateId: 'my_custom_template',  // Must match filename exactly
});

The service.rs layer receives this ID, retrieves the corresponding template from the registry, and delegates to processor.rs for LLM interaction.

Adding a Custom Workflow (Advanced)

For scenarios requiring pre-processing, multi-step prompts, or post-processing, extend the processor directly.

In processor.rs, add a match arm for your template ID:

match template_id {
    "my_custom_template" => {
        // Custom prompt composition logic
        let prompt = format!(
            "{}\n\nAdditional context: {}\n\nTranscript:\n{}",
            CUSTOM_INSTRUCTION,
            fetch_context(),  // e.g., pull related meeting history
            transcript
        );
        generate_summary(&prompt, model).await?;
    }
    _ => default_processing(template_id, transcript, model).await?,
}

Required: Recompile the Tauri app after modifying Rust source:

pnpm run tauri:dev

Testing Your Custom Template

Meetily includes Jest tests for template validation. Add coverage for your custom template:

test('custom template produces valid JSON structure', async () => {
  const content = await readFile(
    'src-tauri/src/summary/templates/custom/my_custom_template.json',
    'utf-8'
  );
  const parsed = JSON.parse(content);
  
  expect(parsed).toHaveProperty('title');
  expect(parsed).toHaveProperty('sections');
  expect(Array.isArray(parsed.sections)).toBe(true);
});

Run the test suite:

pnpm test

Key Configuration Files

File Purpose
defaults.rs Built-in templates (daily_standup, standard_meeting)
loader.rs Dynamic template discovery and registration
template_commands.rs Tauri command API surface
processor.rs LLM prompt construction and invocation
service.rs High-level workflow orchestration

Summary

  • Simple templates: Create JSON in templates/custom/ and restart — no code changes needed
  • Template IDs match filenames without extension
  • Frontend integration uses standard Tauri invoke calls to list_summary_templates and generate_summary
  • Complex workflows require extending processor.rs with custom match arms and recompiling
  • Validate templates with Jest tests before committing to production

Frequently Asked Questions

What is the exact directory path for custom templates?

Place JSON files in frontend/src-tauri/src/summary/templates/custom/ or any subdirectory thereof. The loader.rs implementation recurses through all nested folders.

Do I need to rebuild Meetily after adding a JSON template?

No — for JSON-only templates, a simple application restart suffices. Only modifications to Rust source files (like processor.rs for custom workflows) require recompilation with pnpm run tauri:dev.

Can templates include dynamic variables beyond {{date}}?

The defaults.rs built-ins demonstrate the available interpolation syntax. Custom variables require extending the processor to provide values during prompt construction.

How does Meetily handle template conflicts with identical IDs?

The loader.rs implementation appends user templates after built-ins in the Vec. In case of ID collision, the last-defined template wins — typically the user-provided version.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →