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

# particle_podcast_search_transcripts

> Semantic, keyword, or hybrid search over podcast transcripts — the single way to retrieve relevant dialogue, segments, and clips.

Search the podcast catalog by what is said in episodes — by meaning (`semantic_search`), by exact phrase (`keyword_search`), or both at once (hybrid ranking). This is **THE** way to retrieve relevant dialogue, segments, and clips: each result is one segment of one episode with bounded transcript windows pinpointing the highest-relevance lines, plus any highlight clips that overlap the segment, inline on the match.

<Note>
  This tool replaces the old `search_dialogue` and `list_clips` tools. There is no separate clip-search tool — relevant clips arrive on these matches. A known episode's full clip list is [`particle_podcast_get_episode`](/mcp/tools/podcasts/podcast-get-episode) with `include: ["clips"]`.
</Note>

## Segments vs clips

* **Segments partition an episode's transcript** — where `start_line`/`end_line` are present, every spoken line belongs to exactly one segment and one segment's `end_line + 1` is the next one's `start_line`. They are contiguous in transcript lines, not in wall-clock seconds: the seconds between one segment's `end_seconds` and the next's `start_seconds` contain no transcribed speech. These matches do not carry the line ranges themselves — fetch them with [`particle_podcast_get_episode`](/mcp/tools/podcasts/podcast-get-episode) and `include: ["segments"]`, where their absence marks an episode segmented by an earlier version, a small share of which do leave lines uncovered. Search ranks segments and returns the matching ones.
* **Clips are sparse, engagement-ranked highlights** that overlap some segments. When a clip overlaps a ranked segment, it appears under an `Overlapping clips:` line on that match.

Use this for "find dialogue *about* a topic". For "every line *naming* a person or company" use [`particle_podcast_find_mentions`](/mcp/tools/podcasts/podcast-find-mentions) instead — `person_slug` and `company_slug` here narrow ranked results, they don't drive the ranking.

What `semantic_search` is **not** good at:

| Don't ask it…                                                                                                                                        | Use this instead                                                                                                   |
| ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| "Every line naming OpenAI" — a name, not a topic. Resolving the name and filtering finds the mentions; a vector query drifts to *adjacent* dialogue. | Resolve it, then [`particle_podcast_find_mentions`](/mcp/tools/podcasts/podcast-find-mentions) with `company_slug` |
| An exact token that must appear verbatim — a ticker, model number, or drug name.                                                                     | `keyword_search` (double-quote a phrase for an ordered match)                                                      |

## Crafting the query

`semantic_search` and `keyword_search` do different jobs. Most disappointing
results come from using one where the other belongs.

**`semantic_search` carries the idea.** Write it as a sentence describing what
should be discussed, in the words a speaker would actually use. It is
paraphrase-tolerant, so it finds the topic however it happens to be phrased.

**`keyword_search` carries words that must be literally spoken.** Every word
must appear in the same passage, so it is for one or two exact tokens — a
ticker, a product name, a drug name — not for a description. A sentence here
returns nothing, because no passage contains all of those words.

**Use both when a topic must also contain an exact term.** The result is their
intersection, which is narrow by design. If it comes back empty,
`keyword_match: "ranked"` relaxes the keyword side back to a relevance hint.

| Goal                           | Call                                                                                             |
| ------------------------------ | ------------------------------------------------------------------------------------------------ |
| Dialogue about a topic         | `semantic_search: "how AI is changing entry-level hiring"`                                       |
| A term that must be said       | `keyword_search: "QuillBot"`                                                                     |
| A topic that must name a term  | `semantic_search: "AI writing tools for students"`, `keyword_search: "QuillBot"`                 |
| An exact multi-word string     | `keyword_search: "\"founder mode\""` — quotes require adjacency, so keep them short              |
| Several alternatives           | One call per alternative. There is no boolean `OR` — a bare `OR` is a word that must be spoken   |
| Everything said about a person | Resolve them, then [`particle_podcast_find_mentions`](/mcp/tools/podcasts/podcast-find-mentions) |

<Warning>
  **Never put a name in `semantic_search`.** Resolve it with
  [`particle_person_resolve`](/mcp/tools/people/person-resolve),
  [`particle_company_resolve`](/mcp/tools/companies/company-resolve), or
  [`particle_entity_resolve`](/mcp/tools/people/entity-resolve) and pass the
  slug. Searching for `"Sam Altman"` as text finds passages that *sound like* him;
  `person_slug: "sam-altman"` finds the episodes actually featuring him.
</Warning>

## Start broad, then narrow

Every filter compounds, and each one can remove all results on its own. Issue
the query with `semantic_search` alone first, confirm the topic has coverage,
then add filters.

If a search returns nothing *because of your filters*, the tool returns an error
that names the specific parameter responsible and the corrected call to make —
it is measured by re-running your query with each filter removed, not guessed.
Act on it rather than re-issuing variations of the same query. When the query
text genuinely matches nothing, you get an ordinary empty result instead, which
is the signal to rephrase `semantic_search`.

`role` is the filter most likely to surprise: `guest`/`host`/`panelist`/
`correspondent` mean the person *spoke* in that specific capacity, `speaker`
means they spoke in any of them, and `mention` means they were *talked about*
rather than speaking. Omitting `role` covers speaking and mentions both, and is
almost always what you want. These are the same values `/v1/podcasts/episodes`
accepts.

## Inputs

At least one of `semantic_search` or `keyword_search` is required.

| Field             | Type           | Required | Default     | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ----------------- | -------------- | -------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `semantic_search` | string         | one of   | —           | Vector-similarity search by meaning. Express the query the way you'd describe the topic to a colleague — paraphrase tolerant. Combine with `keyword_search` for hybrid ranking. Describe a *topic*, not a name — for a specific person/company/entity filter with `person_slug`/`company_slug`/`entity_slug` (or use [`particle_podcast_find_mentions`](/mcp/tools/podcasts/podcast-find-mentions) for every line about them); for an exact token use `keyword_search`. |
| `keyword_search`  | string         | one of   | —           | Words that must be literally spoken. Every word must appear in the same passage (see `keyword_match`), so keep it to the one or two words that must be said and put the rest of the idea in `semantic_search`. Double-quote a short string to also require adjacency. No boolean `OR`.                                                                                                                                                                                  |
| `keyword_match`   | string         | no       | `required`  | How **unquoted** `keyword_search` words are applied. `required` excludes any passage missing one of them, which also makes a hybrid call an intersection with `semantic_search`. `ranked` lets those words steer relevance without excluding anything — use it when `keyword_search` is a loose bag of related words that will not co-occur. Quoted phrases filter in **both** modes; to relax a phrase, remove its quotes rather than switching mode.                  |
| `person_slug`     | string         | no       | —           | Person slug from `particle_person_resolve` or `particle_entity_resolve` (e.g. `"sam-altman"`). Filters results to episodes featuring this person. Also accepts a bare entity slug for non-person entities like places. For "every line about X" use `particle_podcast_find_mentions` instead.                                                                                                                                                                           |
| `company_slug`    | string         | no       | —           | Company slug, domain, or ID. Resolves to the company's linked entity and applies as a filter.                                                                                                                                                                                                                                                                                                                                                                           |
| `entity_slug`     | string         | no       | —           | Knowledge-graph entity slug from `particle_entity_resolve` for the long tail that isn't a person or company — places, organizations, events, products, concepts (e.g. `"germany"`). Use `person_slug` for people and `company_slug` for companies.                                                                                                                                                                                                                      |
| `entity_type`     | string         | no       | —           | Narrow to dialogue in episodes that mention any entity of this category — e.g. `book`, `company`, `movie`, `school`. For "discussions of X that reference some book". Ignored when a specific entity is named, which is strictly narrower. Categories come from [`particle_catalog`](/mcp/tools/system/catalog).                                                                                                                                                        |
| `podcast_slug`    | string         | no       | —           | Podcast slug, internal ID, or numeric iTunes ID.                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `episode_slug`    | string         | no       | —           | Filter to a specific episode by slug or ID.                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `segment_type`    | string         | no       | —           | Segment type filter. One of: `INTRO`, `PERSONAL_BANTER`, `TOPIC_DISCUSSION`, `INTERVIEW`, `TRANSITION`, `AD`, `OUTRO`.                                                                                                                                                                                                                                                                                                                                                  |
| `role`            | string         | no       | —           | How the entity must relate to the episode. One of: `guest`, `host`, `panelist`, `correspondent` (spoke in that capacity), `speaker` (spoke in any of them, excluding mention-only episodes), or `mention` (talked about rather than speaking). Omit to match speaking and mentions both.                                                                                                                                                                                |
| `language`        | string         | no       | —           | Restrict to episodes of podcasts in this language — ISO 639-1 code (e.g. `"fr"`). Matches the podcast's primary language subtag, so `fr` covers `fr-FR`.                                                                                                                                                                                                                                                                                                                |
| `since`           | string         | no       | —           | Only segments from episodes published on or after this ISO 8601 date.                                                                                                                                                                                                                                                                                                                                                                                                   |
| `until`           | string         | no       | —           | Only segments from episodes published on or before this ISO 8601 date.                                                                                                                                                                                                                                                                                                                                                                                                  |
| `sort`            | string         | no       | `relevance` | Sort order. One of: `relevance`, `recency`.                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `context`         | integer (1–15) | no       | 1           | Lines of surrounding dialogue around each matched line. Widens each match window **in place** — raise it instead of fetching the full transcript when a match needs more context.                                                                                                                                                                                                                                                                                       |
| `limit`           | integer (1–50) | no       | 10          | Results per page.                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `cursor`          | string         | no       | —           | Opaque pagination cursor.                                                                                                                                                                                                                                                                                                                                                                                                                                               |

## Output

A markdown document with `## Dialogue matches (N)` and one `### Segment title` section per match. Each section carries bulleted KV rows: `- **Episode:**`, `- **Podcast:**`, `- **Podcast slug:**`, `- **Published:**`, `- **Episode slug:**`, `- **Segment type:**`, `- **Match:**` (the source: `semantic`, `keyword`, or `hybrid`), then one or more bullets formatted `Window @ start–end` (or `Preview @ …` for truncated windows) followed by indented dialogue lines. Every line that matched the query is rendered with the entire `Speaker: text` wrapped in bold (a window can contain several matched lines); surrounding context renders as `**Speaker:** text`. When highlight clips overlap the segment, they appear under an `Overlapping clips:` line as bullets formatted `Title (TYPE, score N) @ start–end — clip ID: <id>`. When more pages exist, a horizontal rule and a `**Cursor:** <value>` line are appended.

Bolded lines mark the lines that ranked for the current query (a window can contain several). This is a different signal from the bolding in [`particle_podcast_find_mentions`](/mcp/tools/podcasts/podcast-find-mentions), where a bolded line means "this line names the resolved entity" — they answer different questions and can both be true within the same episode for different reasons.

Sample (`semantic_search="how AI affects the labor market", limit=2`):

```markdown theme={"dark"}
## Dialogue matches (2)

### Labor Market Transformation from AI

- **Episode:** Where Investment Themes Intersect and Beat Markets
- **Podcast:** Thoughts on the Market
- **Podcast slug:** thoughts-on-the-market
- **Published:** 2026-04-20
- **Episode slug:** where-investment-themes-intersect-and-beat-markets
- **Segment type:** TOPIC_DISCUSSION
- **Match:** semantic
- Window @ 108s–143s
    **Stephen Byrd: Now, at the same time, AI is reshaping the labor market.**
    **Stephen Byrd:** And on net, we see a four percent job loss driven by eleven percent of outright elimination…

### Goldman Sachs Report on AI and Job Displacement

- **Episode:** TNB Tech Minute: Thrive Capital and Andreesen Horowitz Co-lead …
- **Podcast:** WSJ Tech News Briefing
- **Podcast slug:** wsj-tech-news-briefing
- **Published:** 2026-03-03
- **Episode slug:** tnb-tech-minute-thrive-capital-and-andreesen-horowitz-co-lead-multibillion
- **Segment type:** TOPIC_DISCUSSION
- **Match:** semantic
- Window @ 43s–67s
    **Danny Lewis: Speaking of AI, a new research report by Goldman Sachs is predicting the technology will eventually displace eleven million jobs…**

Overlapping clips:
- AI to displace 11 million jobs (SHOCKING, score 84) @ 40s–72s — clip ID: e8342676-…
---

**Cursor:** r.4gfFC6
```

The string after `- **Episode slug:**` is what you can feed into [`particle_podcast_get_episode`](/mcp/tools/podcasts/podcast-get-episode) for the full transcript or clip list, or into [`particle_podcast_find_mentions`](/mcp/tools/podcasts/podcast-find-mentions) (`format=detail`, `episode_slug`) for mention windows around a specific person.

## Example

```text theme={"dark"}
Agent calls: particle_podcast_search_transcripts {
  "semantic_search": "how AI affects the labor market",
  "podcast_slug": "all-in",
  "since": "2024-01-01",
  "context": 4,
  "limit": 5
}
```

For hybrid ranking, populate both `semantic_search` and `keyword_search`:

```text theme={"dark"}
Agent calls: particle_podcast_search_transcripts {
  "semantic_search": "what investors think of GPT-5",
  "keyword_search": "GPT-5",
  "limit": 10
}
```

## Related

* REST equivalent: [`GET /v1/podcasts/episodes/search`](/podcasts/episode-search).
* For "every line naming X" use [`particle_podcast_find_mentions`](/mcp/tools/podcasts/podcast-find-mentions).
* For a known episode's full clip list, use [`particle_podcast_get_episode`](/mcp/tools/podcasts/podcast-get-episode) with `include: ["clips"]`.
* For metadata-only episode discovery (no dialogue), use [`particle_podcast_list_episodes`](/mcp/tools/podcasts/podcast-list-episodes).
