> ## Documentation Index
> Fetch the complete documentation index at: https://docs.permutive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Building audiences from an RFP

> Hand an agent an RFP and a skill, and get back the audience tiers it specifies, sized and checked against every requirement.

export const RailStep = ({step, title, note = '', docLink = '', docPages = '', docTitle = 'From the brief — highlighted for this page', docWide = false}) => <li className={step === '1' ? 'agent-chat-rail-step is-active' : 'agent-chat-rail-step'} data-step={step}>
    <a className="agent-chat-note-title" href={`#step-${step}`}>{title}</a>
    <div className="agent-chat-note-body">
      <div>
        {note.split('`').map((part, i) => i % 2 === 1 ? <a key={i} href={`/api/mcp/${part}`}><code>{part}</code></a> : <span key={i}>{part}</span>)}
        {docLink && <button type="button" className="agent-chat-doc-link" popovertarget={`doc-step-${step}`}>
            {docLink} →
          </button>}
      </div>
    </div>
    {docLink && <div id={`doc-step-${step}`} popover="auto" className={docWide ? 'agent-chat-document agent-chat-document-annotated agent-chat-document-wide' : 'agent-chat-document agent-chat-document-annotated'}>
        <div className="agent-chat-document-header">
          <span>{docTitle}</span>
          <button type="button" popovertarget={`doc-step-${step}`} popovertargetaction="hide" aria-label="Close">✕</button>
        </div>
        <div className="agent-chat-document-pages">
          {docPages.split(';').map(src => src.trim()).filter(Boolean).map((src, i) => <img key={src} src={src} alt={`${docTitle}, part ${i + 1}`} noZoom />)}
        </div>
      </div>}
  </li>;

export const StepRail = ({children}) => <aside className="agent-chat-rail" aria-label="Steps">
    <ol className="agent-chat-rail-list">{children}</ol>
  </aside>;

export const ResponsePart = ({step, title, children}) => <section id={`step-${step}`} className="agent-chat-turn agent-chat-part" data-turn-step={step}>
    <div className="agent-chat-turn-label">{step}. {title}</div>
    {children}
  </section>;

export const AnnotatedTurn = ({step, title, children}) => <section id={`step-${step}`} className="agent-chat-turn" data-turn-step={step}>
    <div className="agent-chat-turn-label">{step}. {title}</div>
    {children}
  </section>;

export const AnnotatedConversation = ({children}) => <div className="agent-chat-conversation">{children}</div>;

export const AgentResponse = ({tools = '', skill = '', children}) => <div className="agent-chat-agent">
    {skill && <div className="agent-chat-tools">
        Using skill: <code>{skill}</code>
      </div>}
    {tools && <div className="agent-chat-tools">
        Used Permutive MCP
        {tools.split(',').map(t => t.trim()).filter(Boolean).map((tool, i) => <span key={tool}>
            {i === 0 ? ': ' : ', '}
            <a href={`/api/mcp/${tool}`}><code>{tool}</code></a>
          </span>)}
      </div>}
    <div className="agent-chat-body">{children}</div>
  </div>;

export const UserPrompt = ({children}) => <div className="agent-chat-user">
    <div className="agent-chat-user-bubble">{children}</div>
  </div>;

export const Attachment = ({id, name, kind = '', pages = '', output = false, wide = false, preview = false}) => <div className={output ? 'agent-chat-attachment-row agent-chat-attachment-output' : 'agent-chat-attachment-row'}>
    <button type="button" className={preview ? 'agent-chat-attachment agent-chat-attachment-card' : 'agent-chat-attachment'} popovertarget={id}>
      {preview && <img className="agent-chat-attachment-thumb" src={pages.split(';')[0].trim()} alt={`Preview of ${name}`} noZoom />}
      <span className="agent-chat-attachment-label">
        <span className="agent-chat-attachment-icon" aria-hidden="true">📄</span>
        <span className="agent-chat-attachment-name">{name}</span>
        {kind && <span className="agent-chat-attachment-kind">{kind}</span>}
      </span>
    </button>
    <div id={id} popover="auto" className={wide ? 'agent-chat-document agent-chat-document-wide' : 'agent-chat-document'}>
      <div className="agent-chat-document-header">
        <span>{name}</span>
        <button type="button" popovertarget={id} popovertargetaction="hide" aria-label="Close">✕</button>
      </div>
      <div className="agent-chat-document-pages">
        {pages.split(';').map(src => src.trim()).filter(Boolean).map((src, i) => <img key={src} src={src} alt={`${name}, page ${i + 1}`} noZoom />)}
      </div>
    </div>
  </div>;

<Note>
  The Permutive MCP server is in a **testing phase with partnering customers**.
  Access is invitation-only and the tool interfaces may change. If you would like
  access, please contact your Permutive representative.
</Note>

## Scenario

An RFP arrives as a Word document with detailed requirements: the audiences to build, the minimum
reach for each tier, and the evidence the buyer expects to see.

Normally, you would read through the document and work through every requirement by hand, build and size each
tier against your own data, and write up anything you can't meet.

## How the Permutive MCP server powers the agent

With the Permutive MCP server, your agent is able to automate this by:

* **Work directly from the brief document** — the agent reads the RFP you attach and works
  through each requirement, following a skill that sets out how your team
  answers briefs
* **Build and size every required audience** — cohorts are combined and measured,
  to ensure they accurately meet the market, reach, engagement, etc. the brief specifies
* **Flag what can't be met** — the agent calls out any shortfalls or limitations so that
  your team is informed and can respond honestly to the buyer

## Skill: RFP Audience Response

We created a custom `rfp-audience-response` skill. It tells the agent to:

1. **Work through the brief** — pull out the market, requirements, minimums and
   evidence asked for, then find, compose and measure an audience for each tier
2. **Report every audience in the same shape** — reach, inventory, performance
   against the brief and the cohorts used, so tiers can be compared side by side
3. **Flag what to catch** — at most three caveats, such as requirements met by
   modeled rather than observed data, or signals that contribute almost nothing
4. **Stop before the evidence** — get the recommendation agreed before doing the
   breakdowns, and ask rather than guess when the brief is ambiguous

<Accordion title="About Skills">
  Skills are instructions for your agent that are written once and can then be
  shared across your team. They make sure the same job is done the same way every time.

  Build skills by writing your own instructions, or by asking an agent to write them for you.
  Skills can also include code which allows the agent to do more complicated tasks, such
  as generating a slide deck or spreadsheet, or checking that figures reconcile before they are reported.

  Skills can be used in the following agents:

  * [Claude](https://support.claude.com/en/articles/12512180-using-skills-in-claude)
  * [ChatGPT](https://help.openai.com/en/articles/20001066-skills-in-chatgpt)
  * [Microsoft 365 Copilot](https://learn.microsoft.com/en-us/microsoft-365/copilot/cowork/cowork-customize),
    [PowerPoint](https://support.microsoft.com/en-us/powerpoint/copilot/copilot-in-powerpoint-skills)
    and [Excel](https://support.microsoft.com/en-us/excel/copilot/copilot-in-excel-skills)
  * [Google Gemini](https://support.google.com/gemini/answer/17094296) and
    [Gemini Enterprise](https://docs.cloud.google.com/gemini/enterprise/docs/skills)
</Accordion>

<Accordion title="View the skill">
  ````markdown SKILL.md wrap theme={"dark"}
  ---
  name: rfp-audience-response
  description: "Answer an advertiser RFP or media brief by building and sizing audiences in Permutive, reported in a consistent per-audience format, with supporting evidence gathered only once the recommendation is accepted. Use when given an RFP, brief, or set of audience requirements to build against."
  ---

  # Answering an RFP with audiences

  The reader is the analyst preparing the response. Assume they know the trade and have read the brief — explain neither back to them. Give them figures they can quote, a build they can check, and the caveats they would want to catch before the response goes out.

  ## Steps

  1. **Analyse the brief.** Pull out the market, the audience requirements, the minimum deliverables each audience must hit, and the evidence the response will have to contain. Note which requirements are additive and which are alternatives.

  2. **Find matching cohorts.** Search Permutive for cohorts answering each requirement in turn. Where a cohort family has several depth or recency variants, take the whole family unless the brief narrows the stage of the journey.

  3. **Compose and iterate.** Build each audience, measure it against its minimum, and refine until it meets the requirement — or until you can say precisely why it cannot. Look for additional reach only where a minimum is unmet.

  4. **Recommend, then stop.** Put the audiences forward and get agreement before doing the evidence work. Breakdowns for an audience nobody has signed off on are wasted effort, and the build may change first.

  ## Reporting the audiences

  Open with one line saying whether each audience meets what the brief asked of it.

  Then give every audience the same shape, so they can be read side by side:

  ```
  ## Audience 1: <short name>

  <One sentence describing these people as a persona.>

  * **Reach** — <N> users
  * **Inventory** — <N> page views over the measured window
  * **Against the brief** — <clears / falls short of> the <N> minimum by <N>%
  * **Targeted Cohorts** — Users in <composition, using cohort names joined by AND / OR / NOT>
  ```

  Keep the same bullets, in the same order, for every audience. Add a bullet only if the brief asked for something these do not cover, and then add it to all of them.

  Close with at most three things worth catching before the response goes out, one sentence each, and one line asking whether to gather the evidence the brief asks for. A requirement satisfied by modelled attributes rather than observed behaviour usually belongs there, as does a signal that turns out to contribute almost nothing.

  Name the cohorts in the composition, as above. Keep the raw expression of short ids out of the summary and supply it on request.

  ### Worked example

  > ## Audience 1: Remortgage-ready homeowners
  >
  > Homeowners in their thirties and forties comparing rates and running affordability calculators, who have not just completed a purchase.
  >
  > * **Reach** — 84,000 users
  > * **Inventory** — 412,000 page views (30 days)
  > * **Against the brief** — clears the 50,000 minimum by 68%
  > * **Targeted Cohorts** — Users in (Mortgage Intenders AND Homeowners AND Adults 30+) NOT Recent Completions
  >
  > ## Audience 2: Rate-watchers
  >
  > The same intent behaviour without the age or income filters, carrying reach rather than precision.
  >
  > * **Reach** — 610,000 users
  > * **Inventory** — 3,050,000 page views (30 days)
  > * **Against the brief** — clears the 500,000 minimum by 22%
  > * **Targeted Cohorts** — Users in Mortgage Intenders NOT Recent Completions

  ## Ask rather than guess

  Ask when the answer would change the build and the brief does not settle it:

  - A requirement that reads as either additive or alternative
  - A minimum that cannot be met where more than one requirement could be relaxed, and the choice is the buyer's to make
  - A trade-off between reach and precision with no stated preference
  - Which workspace or market the brief refers to, where more than one fits

  Ask once, put your own recommendation alongside the question, and proceed on that recommendation if no answer comes.

  ## Reporting the evidence

  Once the recommendation is accepted, work through the evidence items the brief asked for, and nothing it did not. If the build changed first, re-measure before reporting.

  ## Style

  - Bullets, not prose. One sentence per bullet where you can, never more than two.
  - Each response should fit one screen. Offer further depth in a closing line rather than including it.
  - Index on a base of 100, with confidence stated before the figure.
  - Give cohort contributions as absolute users rather than percentage shares, since they overlap.
  - State the measurement window once, and say so if you extrapolate it to the flight length.
  ````
</Accordion>

## Example conversation

<AnnotatedConversation>
  <StepRail>
    <RailStep step="1" title="Upload the RFP" note="Attach the RFP to the conversation as you would any file — here, the Word document the buyer sent. The agent reads it directly, so there's no need to copy the requirements into your prompt." />

    <RailStep step="2" title="Hand over the brief" note="Start the skill with its slash command, and give one instruction for the whole job: build the tiers, give the figures, and flag anything you can't meet." docLink="See everything the brief asks for" docPages="/images/mcp/use-cases/aurelia-rfp-highlighted-page-1.png; /images/mcp/use-cases/aurelia-rfp-highlighted-page-2.png" />

    <RailStep step="3" title="Requirements are extracted from the RFP" note="Having read the `rfp-audience-response` skill, the agent pulls out the key requirements and constraints." docLink="See the key points the agent finds" docPages="/images/mcp/use-cases/aurelia-rfp-hl-market.png; /images/mcp/use-cases/aurelia-rfp-hl-deliverables.png" />

    <RailStep step="4" title="A Priority audience is proposed" note="The agent uses the `measure_audiences` tool to iterate and find an audience matching the brief: core intent, qualifying motivation and age, with recent buyers suppressed. The audience clears the 100,000 minimum." docLink="See it in the brief" docPages="/images/mcp/use-cases/aurelia-rfp-hl-requirements-priority.png" />

    <RailStep step="5" title="A Scale tier is proposed" note="Based on its analysis, the agent recommends another audience that was also requested by the RFP" docLink="See it in the brief" docPages="/images/mcp/use-cases/aurelia-rfp-hl-market-intent-motivation.png; /images/mcp/use-cases/aurelia-rfp-hl-suppression-deliverables-head.png; /images/mcp/use-cases/aurelia-rfp-hl-scale.png" />

    <RailStep step="6" title="Gaps are flagged" note="The RFP credits honesty about what can't be met. The agent flags a modeled signal, a near-negligible contributor and a commitment cohort data can't evidence." docLink="See it in the brief" docPages="/images/mcp/use-cases/aurelia-rfp-hl-demographic.png; /images/mcp/use-cases/aurelia-rfp-hl-evidence.png; /images/mcp/use-cases/aurelia-rfp-hl-technical-head.png; /images/mcp/use-cases/aurelia-rfp-hl-technical-suppression.png; /images/mcp/use-cases/aurelia-rfp-hl-scoring.png" />
  </StepRail>

  <AnnotatedTurn step="1" title="Upload the RFP">
    <Attachment id="aurelia-rfp" name="Aurelia_E4_US_RFP.docx" kind="DOCX" pages="/images/mcp/use-cases/aurelia-rfp-page-1.png; /images/mcp/use-cases/aurelia-rfp-page-2.png" />
  </AnnotatedTurn>

  <AnnotatedTurn step="2" title="Hand over the brief">
    <UserPrompt>
      `/rfp-audience-response` Here's an RFP we've received for the Aurelia E4 US
      launch. Build the audience tiers it specifies against our US workspace, and give
      me the figures and evidence it asks for — flag anything we can't meet.
    </UserPrompt>
  </AnnotatedTurn>

  <AgentResponse skill="rfp-audience-response" tools="get_orgs_and_workspaces, get_workspace_details, list_cohorts, measure_audiences">
    <ResponsePart step="3" title="The skill sets the approach">
      I'll start by reading the skill that governs how we respond to these.

      Now measuring the components, US-only, before composing the tiers.

      Both tiers clear their floors on our own observed data — no relaxation needed.
    </ResponsePart>

    <ResponsePart step="4" title="The Priority tier">
      **Audience 1: Priority — E4 switchers 35+**

      Older new-car shoppers who read launch coverage and first-look reviews, and haven't just bought a car.

      * **Reach** — 153,750 users
      * **Inventory** — 830,250 page views (30 days)
      * **Against the brief** — clears the 100,000 minimum by 54%
      * **Market** — measured USA-only; 19.8% of workspace page views sit outside the US and are excluded by country targeting
      * **Targeted Cohorts** — Users in (Auto Intenders \[all five journey variants] AND (Technology Early Adopters \[all variants] OR Sustainability Conscious \[all variants]) AND (Adults 35–44 OR Adults 45–54 OR Adults 55+)) NOT Auto Intenders — recent buyers (90d)
    </ResponsePart>

    <ResponsePart step="5" title="The Scale tier">
      **Audience 2: Scale — E4 switchers, all ages**

      The same intent and motivation without the age filter, carrying campaign reach.

      * **Reach** — 1,558,750 users
      * **Inventory** — 8,417,250 page views (30 days)
      * **Against the brief** — clears the 1,000,000 minimum by 56%
      * **Market** — measured USA-only; same 19.8% non-US exposure excluded by country targeting
      * **Targeted Cohorts** — Users in (Auto Intenders \[all five journey variants] AND (Technology Early Adopters \[all variants] OR Sustainability Conscious \[all variants])) NOT Auto Intenders — recent buyers (90d)
    </ResponsePart>

    <ResponsePart step="6" title="Gaps flagged">
      **Three things to catch before this goes out**

      * The 35+ restriction is met by modelled age brackets (device, content and visit-time patterns), not declared or authenticated data — the only §2 requirement not answered by observed behaviour, and §4 requires us to say so.
      * Sustainability Conscious adds 3,250 net-new users to Priority over Technology Early Adopters alone (150,500 → 153,750), so the qualifying motivation is effectively carried by the tech signal — §4 asks us to declare that rather than let Northgate find it.
      * Our suppression is observed 90-day purchase-completion behaviour on our own properties; suppressing Aurelia's 210,000 owner records is a separate clean-room commitment that cohort data can't evidence.

      Want me to go ahead and gather the §4 evidence for both tiers — reach by property and device, composition by requirement, and whether the 3×/8× cap or our inventory is the binding constraint?
    </ResponsePart>
  </AgentResponse>
</AnnotatedConversation>

## Tips

* **Put your process in the skill**: House rules — which data to trust, how to
  word caveats, what format to answer in — belong in the skill, so every brief is
  answered the same way.
* **Ask for gaps up front**: Buyers credit honesty about requirements you can't
  meet. Asking the agent to flag them gets you a reply you can send.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.