Market Intelligence
287 lines

Plan overview

Weekly Market Intelligence Brief

Research a full week of debt-relief market signals — regulatory enforcement, competitor moves, consumer-lending news, macro developments, and a nine-metric economic dashboard — then render a branded HTML email and send it through Resend. Built to run on a schedule.

Best for

Sales leadership · Marketing · Industry analysts

Runs with

Internet search · Resend · HTML email

At a glance

04

Outputs

02

Capabilities

03

Teams

Core outputs

Leading-indicators dashboard

Regulatory & competitor roundup

Branded HTML email

Delivered via Resend

Capability requirements

Search
MCP

What it solves

A weekly industry brief means one person manually scanning regulators, competitors, and economic data across a dozen sources, then hand-building an email — so it's late, inconsistent, and easy to skip on a busy week.

Turns a manual weekly research-and-build task into a hands-off scheduled run.

Keeps the brief compliance-first and consistent every single week.

Computes and delivers in one plan — no separate reporting or email pipeline.

Workflow

1

Search the week's regulatory, competitor, consumer-lending, marketing, and macro developments in parallel sessions.

2

Pull the latest nine leading economic indicators with prior-period comparisons for the dashboard.

3

Render a branded, mobile-safe HTML brief (with a plain-text fallback) in code and send it through the Resend MCP server.

Implementation

Review the underlying FML plan — the sessions, tools, and typed schemas that define this workflow — and see exactly how it is instructed for repeatable execution.

FML Plan

weekly-brief.fml

287 lines

Copy
system("You are an expert financial researcher and industry analyst for a major debt settlement company.")
require mcp Resend
parameter("timeframe", type=string, default="this past week")
parameter("to_address", type=string, title="To Address")

session("regulatory_news") {
    use search

    + Search for news from {{ .params.timeframe }} regarding the Debt Settlement Industry, focusing on FTC and CFPB regulatory or enforcement developments.

    - Extract the key regulatory updates and general debt settlement industry news.

    schema {
        updates: {
            category: string    # e.g., "FTC Enforcement", "CFPB Rulemaking", "General Industry"
            headline: string
            summary: string     # detailed summary of the news
            sourceUrl?: string
        }[]
    }
}

session("competitor_updates") {
    use search

    + Search for news and developments from {{ .params.timeframe }} for major debt settlement companies: Freedom Debt Relief (Achieve), National Debt Relief, Accredited Debt Relief, Beyond Finance, DebtBlue, Alleviate, ClearOne Advantage, and JG Wentworth.

    - Compile the most significant news, product launches, or leadership changes for these companies.

    schema {
        companyUpdates: {
            companyName: string
            newsSummary: string
            sourceUrl?: string
        }[]
    }
}

session("lending_and_marketing") {
    use search

    + Search for news from {{ .params.timeframe }} on the broader Consumer Lending market.
    + Search for recent marketing trends specific to consumer lending and debt relief, particularly around paid social (TikTok/Meta), lead generation, and marketing compliance.

    - Synthesize the consumer lending news and marketing trends into structured insights.

    schema {
        consumerLendingNews: {
            headline: string
            summary: string
            sourceUrl?: string
        }[]
        marketingTrends: {
            trend: string
            description: string
            complianceNotes: string  # Any regulatory or compliance implications for marketing
        }[]
    }
}

session("macro_economics") {
    use search

    + Search for macroeconomic news from {{ .params.timeframe }} relevant to a debt relief marketing company. Focus heavily on Federal Reserve policy, the jobs market, and inflation reports.

    - Extract the top macroeconomic developments and their potential impact on debt relief demand.

    schema {
        developments: {
            topic: string               # e.g., "Fed Policy", "Inflation", "Jobs"
            summary: string
            impactOnDebtRelief: string  # How this specifically affects the debt relief sector
        }[]
    }
}

session("economic_dashboard") {
    use search

    + Find the most recently published data (from FRED or the Federal Reserve) for the following indicators:
      1. Fed funds rate
      2. Unemployment rate
      3. Labor force participation
      4. Personal savings rate
      5. Total household debt
      6. Credit card balances
      7. Credit card delinquency rate
      8. Credit card charge-off rate
      9. Average credit card APR
      Look for current values and prior-period comparisons.

    - Extract the data to populate the Leading Indicators Dashboard.

    schema {
        metrics: {
            indicator: string         # The name of the economic indicator
            currentValue: string      # The most recent value (include date/period if known)
            priorPeriodValue: string  # The value from the previous reporting period
            trend: string             # "Up", "Down", or "Flat"
            source: string            # Data source, e.g., "FRED", "Federal Reserve"
        }[]
    }
}

session("send_email", after="economic_dashboard") {
    use mcp Resend

    # ── Render the branded HTML (+ plain-text fallback) from all session
    #    outputs. Resend cannot loop over arrays, so we build the rows here and hand
    #    finished html/text to send-email. Result is routed to vars.email.
    call("render_email") -> vars:email {
        code(
            (
                const esc = (s) => String(s == null ? '' : s)
                    .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
                    .replace(/"/g, '&quot;').replace(/'/g, '&#x27;');

                const NAVY = '#031D48', GOLD = '#D4A72C', GOLD_LT = '#F4C94E', INK = '#31384A',
                      MUTE = '#6B7385', FAINT = '#9AA1B0', LINE = '#E3E7EF', ZEBRA = '#F7F9FC', BG = '#EEF1F6';
                const FONT = "'Segoe UI',Arial,Helvetica,sans-serif";

                const d = args.data || {};
                const timeframe = args.timeframe || '';
                const unsub = args.unsub || '#';
                const recipient = 'the Sales Management Team';

                const metrics = ((d.economic_dashboard || {}).metrics) || [];
                const devs    = ((d.macro_economics || {}).developments) || [];
                const regs    = ((d.regulatory_news || {}).updates) || [];
                const comps   = ((d.competitor_updates || {}).companyUpdates) || [];
                const lend    = ((d.lending_and_marketing || {}).consumerLendingNews) || [];
                const mkt     = ((d.lending_and_marketing || {}).marketingTrends) || [];

                const intro = "This week's signals continue to favor the debt-relief category: household debt, "
                    + "credit card balances, delinquency and charge-off rates are all rising while incomes stay "
                    + "capped, even as the Fed holds a higher for longer stance. Regulatory enforcement "
                    + "remains active, so compliance-first positioning stays essential. Details below.";

                const trend = (t) => {
                    const k = String(t || '').toLowerCase();
                    if (k === 'up')   return ['&#9650;', 'Up', '#1E8E5A'];
                    if (k === 'down') return ['&#9660;', 'Down', '#C0392B'];
                    return ['&#9644;', 'Flat', MUTE];
                };
                const hdr = (title) =>
                    '<tr><td class="px" style="padding:30px 32px 0 32px;"><table role="presentation" width="100%" cellpadding="0" cellspacing="0"><tr>'
                    + '<td style="border-left:4px solid ' + GOLD + ';padding:2px 0 2px 12px;"><h2 style="margin:0;font-family:' + FONT + ';font-size:16px;font-weight:700;letter-spacing:0.6px;color:' + NAVY + ';text-transform:uppercase;">' + esc(title) + '</h2></td>'
                    + '</tr></table></td></tr>';

                const dashRows = metrics.map((m, i) => {
                    const bg = i % 2 ? ZEBRA : '#FFFFFF';
                    const tr = trend(m.trend);
                    return '<tr>'
                        + '<td style="padding:11px 14px;font-family:' + FONT + ';font-size:13px;color:' + INK + ';border-top:1px solid ' + LINE + ';background-color:' + bg + ';">' + esc(m.indicator) + '</td>'
                        + '<td style="padding:11px 14px;font-family:' + FONT + ';font-size:13px;font-weight:700;color:' + NAVY + ';border-top:1px solid ' + LINE + ';background-color:' + bg + ';">' + esc(m.currentValue) + '</td>'
                        + '<td style="padding:11px 14px;font-family:' + FONT + ';font-size:13px;color:' + MUTE + ';border-top:1px solid ' + LINE + ';background-color:' + bg + ';">' + esc(m.priorPeriodValue) + '</td>'
                        + '<td align="center" style="padding:11px 14px;font-family:' + FONT + ';font-size:13px;font-weight:700;color:' + tr[2] + ';border-top:1px solid ' + LINE + ';background-color:' + bg + ';white-space:nowrap;">' + tr[0] + '&nbsp;' + tr[1] + '</td>'
                        + '<td style="padding:11px 14px;font-family:' + FONT + ';font-size:11px;color:' + FAINT + ';border-top:1px solid ' + LINE + ';background-color:' + bg + ';">' + esc(m.source) + '</td>'
                        + '</tr>';
                }).join('');

                const dashboard =
                    '<tr><td class="px" style="padding:14px 32px 0 32px;"><table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border:1px solid ' + LINE + ';border-radius:8px;overflow:hidden;">'
                    + '<tr>'
                    + '<td style="background-color:' + NAVY + ';padding:11px 14px;font-family:' + FONT + ';font-size:11px;font-weight:700;letter-spacing:0.5px;color:#FFFFFF;text-transform:uppercase;">Indicator</td>'
                    + '<td style="background-color:' + NAVY + ';padding:11px 14px;font-family:' + FONT + ';font-size:11px;font-weight:700;letter-spacing:0.5px;color:#FFFFFF;text-transform:uppercase;">Current</td>'
                    + '<td style="background-color:' + NAVY + ';padding:11px 14px;font-family:' + FONT + ';font-size:11px;font-weight:700;letter-spacing:0.5px;color:#FFFFFF;text-transform:uppercase;">Prior</td>'
                    + '<td align="center" style="background-color:' + NAVY + ';padding:11px 14px;font-family:' + FONT + ';font-size:11px;font-weight:700;letter-spacing:0.5px;color:' + GOLD_LT + ';text-transform:uppercase;">Trend</td>'
                    + '<td style="background-color:' + NAVY + ';padding:11px 14px;font-family:' + FONT + ';font-size:11px;font-weight:700;letter-spacing:0.5px;color:#FFFFFF;text-transform:uppercase;">Source</td>'
                    + '</tr>' + dashRows + '</table>'
                    + '<p style="margin:8px 0 0 0;font-family:' + FONT + ';font-size:11px;color:' + FAINT + ';">Trend reflects directional change vs. the prior reporting period: &#9650; Up &nbsp;&#9660; Down &nbsp;&#9644; Flat.</p></td></tr>';

                const macro = devs.map((x) =>
                    '<tr><td class="px" style="padding:14px 32px 0 32px;"><table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border:1px solid ' + LINE + ';border-radius:8px;"><tr><td style="padding:14px 16px;">'
                    + '<p style="margin:0 0 6px 0;font-family:' + FONT + ';font-size:12px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;color:' + GOLD + ';">' + esc(x.topic) + '</p>'
                    + '<p style="margin:0 0 10px 0;font-family:' + FONT + ';font-size:14px;line-height:21px;color:' + INK + ';">' + esc(x.summary) + '</p>'
                    + '<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:' + ZEBRA + ';border-radius:6px;"><tr><td style="padding:10px 12px;font-family:' + FONT + ';font-size:13px;line-height:20px;color:' + NAVY + ';"><span style="font-weight:700;color:' + GOLD + ';">Impact on debt relief:</span> ' + esc(x.impactOnDebtRelief) + '</td></tr></table>'
                    + '</td></tr></table></td></tr>').join('');

                const regulatory = regs.map((u) => {
                    const link = u.sourceUrl ? ' &nbsp;<a href="' + esc(u.sourceUrl) + '" style="color:' + GOLD + ';text-decoration:underline;font-size:12px;">Source &#8599;</a>' : '';
                    return '<tr><td class="px" style="padding:14px 32px 0 32px;"><table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border:1px solid ' + LINE + ';border-left:4px solid ' + NAVY + ';border-radius:6px;"><tr><td style="padding:13px 16px;">'
                        + '<span style="display:inline-block;background-color:' + NAVY + ';color:' + GOLD_LT + ';font-family:' + FONT + ';font-size:10px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;padding:3px 8px;border-radius:3px;">' + esc(u.category) + '</span>'
                        + '<p style="margin:9px 0 5px 0;font-family:' + FONT + ';font-size:15px;font-weight:700;line-height:21px;color:' + NAVY + ';">' + esc(u.headline) + '</p>'
                        + '<p style="margin:0;font-family:' + FONT + ';font-size:13px;line-height:20px;color:' + INK + ';">' + esc(u.summary) + link + '</p>'
                        + '</td></tr></table></td></tr>';
                }).join('');

                const competitorRows = comps.map((c, i) => {
                    const bg = i % 2 ? ZEBRA : '#FFFFFF';
                    return '<tr>'
                        + '<td valign="top" width="34%" style="padding:12px 14px;font-family:' + FONT + ';font-size:14px;font-weight:700;color:' + NAVY + ';border-top:1px solid ' + LINE + ';background-color:' + bg + ';">' + esc(c.companyName) + '</td>'
                        + '<td valign="top" style="padding:12px 14px;font-family:' + FONT + ';font-size:13px;line-height:20px;color:' + INK + ';border-top:1px solid ' + LINE + ';background-color:' + bg + ';">' + esc(c.newsSummary) + '</td>'
                        + '</tr>';
                }).join('');
                const competitors =
                    '<tr><td class="px" style="padding:14px 32px 0 32px;"><table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border:1px solid ' + LINE + ';border-radius:8px;overflow:hidden;">'
                    + '<tr><td style="background-color:' + NAVY + ';padding:11px 14px;font-family:' + FONT + ';font-size:11px;font-weight:700;letter-spacing:0.5px;color:#FFFFFF;text-transform:uppercase;">Company</td>'
                    + '<td style="background-color:' + NAVY + ';padding:11px 14px;font-family:' + FONT + ';font-size:11px;font-weight:700;letter-spacing:0.5px;color:' + GOLD_LT + ';text-transform:uppercase;">This Week</td></tr>'
                    + competitorRows + '</table></td></tr>';

                const lending = lend.map((it) => {
                    const link = it.sourceUrl ? ' &nbsp;<a href="' + esc(it.sourceUrl) + '" style="color:' + GOLD + ';text-decoration:underline;font-size:12px;">Source &#8599;</a>' : '';
                    return '<tr><td class="px" style="padding:12px 32px 0 32px;"><table role="presentation" width="100%" cellpadding="0" cellspacing="0"><tr>'
                        + '<td valign="top" width="10" style="padding-top:6px;"><div style="width:7px;height:7px;background-color:' + GOLD + ';border-radius:50%;"></div></td>'
                        + '<td style="padding-left:10px;"><p style="margin:0 0 3px 0;font-family:' + FONT + ';font-size:14px;font-weight:700;color:' + NAVY + ';">' + esc(it.headline) + '</p>'
                        + '<p style="margin:0;font-family:' + FONT + ';font-size:13px;line-height:20px;color:' + INK + ';">' + esc(it.summary) + link + '</p></td>'
                        + '</tr></table></td></tr>';
                }).join('');

                const marketing = mkt.map((t) =>
                    '<tr><td class="px" style="padding:12px 32px 0 32px;"><table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border:1px solid ' + LINE + ';border-radius:8px;"><tr><td style="padding:13px 16px;">'
                    + '<p style="margin:0 0 6px 0;font-family:' + FONT + ';font-size:14px;font-weight:700;color:' + NAVY + ';">' + esc(t.trend) + '</p>'
                    + '<p style="margin:0 0 9px 0;font-family:' + FONT + ';font-size:13px;line-height:20px;color:' + INK + ';">' + esc(t.description) + '</p>'
                    + '<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:#FBF4DE;border-radius:6px;"><tr><td style="padding:9px 12px;font-family:' + FONT + ';font-size:12px;line-height:18px;color:#6A5410;"><span style="font-weight:700;">Compliance:</span> ' + esc(t.complianceNotes) + '</td></tr></table>'
                    + '</td></tr></table></td></tr>').join('');

                const html =
                    '<!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"><head>'
                    + '<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="x-apple-disable-message-reformatting">'
                    + '<title>Your Company  Weekly Intelligence Brief</title>'
                    + '<!--[if mso]><noscript><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml></noscript><![endif]-->'
                    + '<style>body,table,td,a{-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}table,td{mso-table-lspace:0pt;mso-table-rspace:0pt;}img{-ms-interpolation-mode:bicubic;border:0;}table{border-collapse:collapse!important;}body{margin:0!important;padding:0!important;width:100%!important;background-color:' + BG + ';}@media screen and (max-width:600px){.container{width:100%!important;}.px{padding-left:18px!important;padding-right:18px!important;}.h1{font-size:22px!important;line-height:28px!important;}}</style></head>'
                    + '<body style="margin:0;padding:0;background-color:' + BG + ';">'
                    + '<div style="display:none;max-height:0;overflow:hidden;mso-hide:all;font-size:1px;line-height:1px;color:' + BG + ';">Weekly debt-relief market intelligence.</div>'
                    + '<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:' + BG + ';"><tr><td align="center" style="padding:24px 12px;">'
                    + '<table role="presentation" class="container" width="640" cellpadding="0" cellspacing="0" style="width:640px;max-width:640px;background-color:#FFFFFF;border-radius:10px;overflow:hidden;box-shadow:0 2px 8px rgba(3,29,72,0.08);">'
                    + '<tr><td style="background-color:' + NAVY + ';padding:22px 32px;" class="px"><table role="presentation" width="100%" cellpadding="0" cellspacing="0"><tr>'
                    + '<td align="left" style="font-family:' + FONT + ';font-size:24px;font-weight:800;letter-spacing:1.5px;color:#FFFFFF;">YOUR<span style="color:' + GOLD_LT + ';">BRAND</span></td>'
                    + '<td align="right" style="font-family:' + FONT + ';font-size:11px;font-weight:600;letter-spacing:1px;color:' + GOLD + ';text-transform:uppercase;">Weekly Intelligence Brief</td>'
                    + '</tr></table></td></tr>'
                    + '<tr><td style="height:4px;background-color:' + GOLD + ';line-height:4px;font-size:0;">&nbsp;</td></tr>'
                    + '<tr><td class="px" style="padding:30px 32px 6px 32px;">'
                    + '<p style="margin:0 0 6px 0;font-family:' + FONT + ';font-size:12px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:' + GOLD + ';">Debt Relief Market Intelligence</p>'
                    + '<h1 class="h1" style="margin:0;font-family:' + FONT + ';font-size:26px;line-height:32px;font-weight:800;color:' + NAVY + ';">Weekly Sales Brief</h1>'
                    + '<p style="margin:10px 0 0 0;font-family:' + FONT + ';font-size:13px;color:' + MUTE + ';">Week of ' + esc(timeframe) + ' &nbsp;&bull;&nbsp; Prepared for ' + esc(recipient) + '</p></td></tr>'
                    + '<tr><td class="px" style="padding:16px 32px 0 32px;"><p style="margin:0;font-family:' + FONT + ';font-size:14px;line-height:22px;color:' + INK + ';">' + esc(intro) + '</p></td></tr>'
                    + hdr('Economic Dashboard  Leading Indicators') + dashboard
                    + hdr('Macro-Economic Developments') + macro
                    + hdr('Regulatory News') + regulatory
                    + hdr('Competitor Updates') + competitors
                    + hdr('Consumer Lending News') + lending
                    + hdr('Marketing Trends') + marketing
                    + '<tr><td style="height:12px;line-height:12px;font-size:0;">&nbsp;</td></tr>'
                    + '<tr><td style="background-color:' + NAVY + ';padding:26px 32px;" class="px">'
                    + '<p style="margin:0 0 4px 0;font-family:' + FONT + ';font-size:16px;font-weight:800;letter-spacing:1px;color:#FFFFFF;">YOUR<span style="color:' + GOLD_LT + ';">BRAND</span></p>'
                    + '<p style="margin:0 0 12px 0;font-family:' + FONT + ';font-size:12px;line-height:18px;color:#9FB0CC;">Your Company &nbsp;&bull;&nbsp; Weekly Market Intelligence for the Sales Team</p>'
                    + '<p style="margin:0;font-family:' + FONT + ';font-size:11px;line-height:18px;color:#6E82A6;">You\'re receiving this because you\'re part of your company\'s distribution list.<br>'
                    + '<a href="' + esc(unsub) + '" style="color:' + GOLD + ';text-decoration:underline;">Unsubscribe</a></p></td></tr>'
                    + '</table></td></tr></table></body></html>';

                const L = (s) => String(s == null ? '' : s);
                let text = 'YOURBRAND  WEEKLY SALES BRIEF\nWeek of ' + timeframe + ' | Prepared for ' + recipient + '\n============================================================\n\n' + intro + '\n\nECONOMIC DASHBOARD  LEADING INDICATORS\n';
                metrics.forEach((m) => { text += '* ' + L(m.indicator) + ': ' + L(m.currentValue) + ' (prior ' + L(m.priorPeriodValue) + '; ' + L(m.trend) + ') [' + L(m.source) + ']\n'; });
                text += '\nMACRO-ECONOMIC DEVELOPMENTS\n';
                devs.forEach((x) => { text += '# ' + L(x.topic) + '\n' + L(x.summary) + '\nImpact: ' + L(x.impactOnDebtRelief) + '\n\n'; });
                text += 'REGULATORY NEWS\n';
                regs.forEach((u) => { text += '[' + L(u.category) + '] ' + L(u.headline) + '\n' + L(u.summary) + '\n' + (u.sourceUrl ? 'Source: ' + L(u.sourceUrl) + '\n' : '') + '\n'; });
                text += 'COMPETITOR UPDATES\n';
                comps.forEach((c) => { text += '# ' + L(c.companyName) + '\n' + L(c.newsSummary) + '\n\n'; });
                text += 'CONSUMER LENDING NEWS\n';
                lend.forEach((it) => { text += '* ' + L(it.headline) + '\n' + L(it.summary) + '\n'; });
                text += '\nMARKETING TRENDS\n';
                mkt.forEach((t) => { text += '# ' + L(t.trend) + '\n' + L(t.description) + '\nCompliance: ' + L(t.complianceNotes) + '\n\n'; });
                text += '============================================================\nUnsubscribe: ' + unsub + '\n';

                ({ html: html, text: text });
            )
        )
        data = $( context )
        timeframe = "{{ .params.timeframe }}"
        unsub = "https://example.com/unsubscribe"
    }

    call("send-email") {
        to = $( [params.to_address] )
        from = "notifications@ai.example.com"
        subject = "Weekly Industry Brief: {{ .params.timeframe }}"
        html = $( vars.email.html )
        text = "{{ .context | json }}"
    }

    - Output true for sentSuccessfully to confirm the session ran.
    schema {
        sentSuccessfully: bool
    }
}