Podlex

Podlex plugs into Claude or ChatGPT and hands it a catalogue of 4.8 million podcasts — who makes each show, what it's really for, how much of it is AI, and…

От сообщества: Добавлен пользователем или импортирован; проверьте владельца перед подключениемРаботаетБез входаГлобальныйБесплатноТолько чтение

Что умеет

  • Search Podcasts: Free-text search over podcast titles, descriptions and author fields, with optional filters on how the show is classified. When to use: - You know roughly what the show is about, or w
  • Search Episodes: Free-text search over episode titles and descriptions across every episode in the catalogue. When to use: - Find episodes that mention a company, a person or a product. - Read what a
  • Find Podcasts: Finds podcasts by what they are rather than by what they say — structured filters over the classification layer, no search text needed. When to use: - "Every brand-marketing show publis

Какие данные видит

Нужен ли аккаунт

Не нужен: сервер работает без входа

Podlex plugs into Claude or ChatGPT and hands it a catalogue of 4.8 million podcasts — who makes each show, what it's really for, how much of it is AI, and whether it's still going. No audio and no listener numbers: Podlex knows what shows are, not how they perform. Ask in plain English, or query the catalogue directly with read-only SQL.

Список инструментов сервера (10)

Технические названия из tools/list. Нужны только разработчикам.

search_podcastsFree-text search over podcast titles, descriptions and author fields, with optional filters on how the show is classified. When to use: - You know roughly what the show is about, or who makes it, and want to find it. - You want every show that mentions a company, a person or a topic. - You want to narrow a broad topic by who publishes it or why (publisher_kind, show_purpose, ai_production_level). Parameters: - text (required): a full-text query over the show's title, description and author fields. Plain words are the common case and need no syntax: every word has to appear somewhere in the record, in any order. The operators are real and cost nothing to use — "venture capital" for the exact phrase, marketing OR business, marketing NOT ai, NEAR(ai podcast, 5) for words close together, title:marketing to search one field, acquisit* to search by prefix. AND / OR / NOT / NEAR must be uppercase; the fields you can put before a colon are title, description and itunes_author. NEAR's integer counts the words allowed between yours, so NEAR(a b, 0) means adjacent. A prefix needs at least 3 characters before the *, which is a courtesy so you get an instant refusal rather than a timeout, not a limit that protects anything. The index is stemmed before the * is applied, so a prefix reaches sideways as well as further along — marketing* scans from market and finds marketplace — and you will often not need it at all, since acquisition already matches acquisitions. An expression the query language cannot parse is refused, with the fix and with your own words requoted so the operators are off. That is not a literal search: quoting switches the query language off but not the index, which holds words and no punctuation, so "co-op" is co followed by op and nothing here can search for the punctuation itself. "Cost nothing" is measured rather than asserted: on the 4.83M shows searched here, 2026-07-31 against a 15s deadline, every example above answers in about a second, every one of them, and a prefix is cheap at every length anyone has measured — acq* 0.5s, mar* 1.3s, the* 5s. search_episodes is a different population and its description says so; do not carry these numbers over. - publisher_kind (optional): company / nonprofit / government / educational_institution / media_business / individual / ai_factory / derivative_fan_or_anonymous / unknown. - show_purpose (optional): brand_marketing / revenue_business / mission / internal / personal / derivative_fan_work / unknown. - ai_production_level (optional): human / ai_assisted / ai_narrated / fully_ai_generated / unknown. - region (optional): us / uk / eu / apac / latam / mena / africa / global / other / unknown. - industry (optional): the publisher's industry, matched exactly. describe_schema lists the vocabulary. - language (optional): RSS language code, e.g. en, en-us, de. - max_results (default 50, max 500). Returns one row per podcast, ordered by relevance: podcast_id, title, publisher_company, publisher_entity_name, publisher_kind, show_purpose, ai_production_level, industry, region, language, latest_episode_at, actual_episode_count, is_stale_18mo, is_cadence_broken, score (lower is a better match). podcast_id is an opaque handle — pass it to get_podcast for the full record, or to search_episodes to search inside one show.
search_episodesFree-text search over episode titles and descriptions across every episode in the catalogue. When to use: - Find episodes that mention a company, a person or a product. - Read what a single show has covered, by passing its podcast_id — that is the cheap way to search, not just the narrow one. - Bound a search in time with after_date / before_date. They filter what comes back rather than what is searched, so they narrow the answer and not the work. Parameters: - text (required): a full-text query over the episode's title and description. Plain words are the common case and need no syntax: every word has to appear somewhere in the record, in any order. The operators are real and none of them costs anything by itself — "venture capital" for the exact phrase, acquisit* to search by prefix, title:marketing to search one field, NEAR(ai podcast, 5) for words close together, marketing NOT ai, marketing OR business. AND / OR / NOT / NEAR must be uppercase; the fields you can put before a colon are title and description. NEAR's integer counts the words allowed between yours, so NEAR(a b, 0) means adjacent. A prefix needs at least 3 characters before the *, which is a courtesy so you get an instant refusal rather than a timeout, not a limit that protects anything. The index is stemmed before the * is applied, so a prefix reaches sideways as well as further along — marketing* scans from market and finds marketplace — and you will often not need it at all, since acquisition already matches acquisitions. An expression the query language cannot parse is refused, with the fix and with your own words requoted so the operators are off. That is not a literal search: quoting switches the query language off but not the index, which holds words and no punctuation, so "co-op" is co followed by op and nothing here can search for the punctuation itself. What a search costs here is how many of the 131M episodes your WORDS reach, not which operator you wrote, and without podcast_id that is the whole story. Measured on this catalogue 2026-07-31 against a 15s deadline: "venture capital" 1.1s, acquisit* 1.2s, title:marketing 3.2s — but the single common word marketing is 7.8s, marketing NOT ai 8.5s, NEAR(ai podcast, 5) 10.0s, and marketing OR business does not finish at all and is killed. So a distinctive word, a phrase or a column filter is cheap; one very common word is most of your budget; two of them joined by OR is past it. Prefer the specific term, and add words to narrow rather than OR to widen. With podcast_id none of that applies: the search runs over an index built for that one show, so the cost is the size of the show. Every expression above answers in under a second on a 69-episode show and in 1.6s on a 1,346-episode one, marketing OR business included. - podcast_id (optional): an opaque podcast id from search_podcasts or find_podcasts. Searches that one show. It is genuinely cheaper and not merely narrower — the search runs over an index built for that show alone, so what it costs is the size of the show rather than how common your words are across the catalogue. - after_date / before_date (optional): ISO date (2024-01-01) or unix epoch. - max_results (default 50, max 500). Returns one row per episode, ordered by relevance: episode_id, podcast_id, podcast_title, title, date_published, duration, link, enclosure_url, score (lower is a better match). score is a relevance rank, and with podcast_id set it ranks within that show — the same ordering rule against a different set of episodes, so the numbers are not comparable between a scoped call and an unscoped one. Order and meaning are. enclosure_url is the audio file as the publisher serves it. date_published is a unix timestamp.
find_podcastsFinds podcasts by what they are rather than by what they say — structured filters over the classification layer, no search text needed. When to use: - "Every brand-marketing show published by a company in Financial Services." - "AI-narrated shows in the us region that have stopped publishing." - "Everything this publisher makes" (publisher_kind plus publisher_company). Two lenses people ask for by name: - AI podcast factories — entities mass-producing machine-made shows as their business: publisher_kind='ai_factory'. Add ai_production_level='fully_ai_generated' for the fully synthetic end of it, whoever publishes it. - Solo creators, including the LLC-wrapped ones: publisher_kind='individual', usually with show_purpose='personal'. At least one of publisher_kind, show_purpose, ai_production_level, industry, region, host is required. Those are the ones the catalogue can seek straight into and get back a workable slice; language, is_stale_18mo, is_cadence_broken, publisher_company, min_episodes, published_since are real filters that cannot do that — either there is no index to seek, or the seek hands back most of the catalogue anyway — so they narrow a cohort the required ones have already chosen rather than choosing one themselves. Parameters: - publisher_kind: company / nonprofit / government / educational_institution / media_business / individual / ai_factory / derivative_fan_or_anonymous / unknown. - show_purpose: brand_marketing / revenue_business / mission / internal / personal / derivative_fan_work / unknown. - ai_production_level: human / ai_assisted / ai_narrated / fully_ai_generated / unknown. - industry: the publisher's industry, matched exactly. describe_schema lists the vocabulary. - region: us / uk / eu / apac / latam / mena / africa / global / other / unknown. - host: the domain serving the RSS feed, matched exactly (e.g. anchor.fm). - language: RSS language code (en, de, ...). - is_stale_18mo: 1 for shows with no episode in 18 months, 0 for the rest. - is_cadence_broken: 1 for shows publishing far slower than they used to. - publisher_company: the publisher's canonical name, matched as a case-insensitive substring. A substring cannot be sought to, so pair it with one of the required filters — and note the substring is then tested over every show of that filter's cohort, which makes a rare name under a broad publisher_kind the slow pairing. - min_episodes: only shows with at least this many episodes. - published_since: ISO date or unix epoch — only shows with an episode at or after it. - order_by (optional): 'episodes' for the biggest shows first, 'recent' for the most recently published. Left out, rows come back in index order — which is several times faster, because sorting is paid over every matching show rather than the ones returned. - max_results (default 50, max 500). Returns podcast rows: podcast_id, publisher_id, title, publisher_company, publisher_entity_name, publisher_kind, show_purpose, ai_production_level, industry, region, language, latest_episode_at, actual_episode_count, is_stale_18mo, is_cadence_broken. Looking for a show or a person by name? search_podcasts(text=..., publisher_kind=...) searches titles, descriptions and author fields, and takes the same filters.
get_podcastFetches everything the catalogue holds about one podcast, by its opaque podcast_id. Instant. When to use: - You have a podcast_id from search_podcasts, find_podcasts or search_episodes, and want the full record rather than the summary columns. Parameters: - podcast_id (required): an opaque id, e.g. pdx_0a1b2c3d4e. Returns one row with feed_id — the numeric join key, and the bridge from the opaque podcast_id you already hold to the indexed path into episodes: in query_sql, SELECT ... FROM episodes WHERE feed_id = <that number> is the only episodes query that is not a full scan, so this is where you get the number. Alongside it: the RSS metadata (url, title, description, link, language, image_url, itunes_* fields), the cadence signals we compute from the episodes we hold (actual_episode_count, oldest_episode_at, latest_episode_at, median_interval_days, is_stale_18mo, is_cadence_broken), and the enrichment layer: who publishes it (publisher_entity_name, publisher_kind, publisher_company, publisher_domain, publisher_confidence, publisher_evidence), who produced the audio (production_company, production_company_id), why the show exists (show_purpose), and how much of the audio is machine-made (ai_production_level, ai_tools_mentioned). No rows means either that no podcast has that id, or that the id belongs to a different kind of thing — an episode id and a podcast id are shaped alike but are not interchangeable. Use describe_schema for what each column means, and search_episodes(podcast_id=...) for what the show has covered.
get_publisherFetches one publisher — a company, institution or individual that publishes podcasts — by its opaque publisher_id, with the rollups across everything it publishes. When to use: - You have a publisher_id from a podcast row (publisher_id or production_company_id), returned by search_podcasts or find_podcasts, and want the whole portfolio picture. Parameters: - publisher_id (required): an opaque id, e.g. pdx_0a1b2c3d4e. Returns one row: publisher_id, canonical_name, primary_domain, podcast_count, stale_count (shows with no episode for 18 months), cadence_broken_count (shows publishing far slower than they used to), ai_produced_show_count, dominant_industry, dominant_region, and podcast_titles — up to 50 of its show titles, most episodes first, as a JSON *string* you have to parse rather than as an array. SQLite builds it with json_group_array and nothing parses it on the way out; it is `[]` for a publisher with no shows. The counts are over shows this publisher CONTROLS. A production company that makes audio for other people will show low counts here even when it produced a great deal — production credits live on the podcast row as production_company / production_company_id. Want the shows themselves as rows? find_podcasts(publisher_kind=..., publisher_company=...) — publisher_company narrows rather than leads, so it needs one of the indexed filters beside it, and publisher_kind is on every podcast row this publisher appears on.
query_sqlRun an ad-hoc read-only SQL query against the public podcast catalogue. For questions the other tools don't cover — prefer search_podcasts / search_episodes / find_podcasts when they fit, since they're indexed and much faster. You can query: feeds, episodes, companies — the public projection of each, not the stored table. Use describe_schema for the columns and list_example_queries for working examples. Two things a stranger trips on. Name an object plainly (`FROM feeds`, or `FROM temp.feeds` if you like being explicit): a `main.` prefix asks for our own storage, which is not on this surface at all and does not resolve. And size is the thing to plan around rather than syntax: `feeds` is 4.83M rows and answers a count, a GROUP BY or a DISTINCT over the whole of itself in about a second — up to 6s on `show_purpose`, the widest column, so budget seconds rather than none — while `episodes` is 131M rows and will not, at any budget. Scope an episodes query with `WHERE feed_id = ?` (0.11s), or use search_episodes, which is indexed. Guardrails (in this order): 1. Single read-only SELECT — SELECT, WITH ... SELECT, VALUES and compound SELECTs. Writes, PRAGMA and multiple statements are refused; the catalogue is read-only for everyone, always. 2. Public catalogue only — every name is resolved by SQLite against the public schema, and every B-tree the compiled query opens is checked, so views, CTEs and subqueries cannot reach anything else. 3. Row and byte caps — 1,000 rows or 1 MB, whichever comes first, counted as the rows are read. A truncated result says so in _warnings. 4. 15-second hard deadline, enforced by killing the worker running the query. This is the only thing that stops an expensive statement: nothing is refused for its cost, so a query too big to finish is run and then killed rather than turned away, and what you get back is the deadline message with the shapes that do work. Every refusal explains what happened and how to get in touch if the limit is the problem — we would rather hear the question than have you go without. Parameters: - sql (required): a single SELECT (or WITH ... SELECT) statement. Returns: { rows, _row_count, _sql_used, _explain_plan, _warnings }.
describe_schemaReturns the public catalogue's schema: every object, every column, its type, what it means, and the values it accepts. When to use: - Before writing a query_sql, to see what exists. - To look up the accepted values for publisher_kind / show_purpose / ai_production_level / region. - To understand what a column actually measures before trusting it. Each column comes with name, type and nullable. It also carries a description, unless the name is the whole of what the column means, and an enum where the values are a fixed vocabulary. The objects: feeds (podcasts, one row per show), episodes (one row per episode) and companies (publishers, with rollups across everything they publish). Three, and no views — a cut like "AI factories" or "solo creators" is an indexed predicate on feeds (publisher_kind, show_purpose, ai_production_level), which is both faster and yours to compose. list_indexes shows which columns have an index behind them. One numeric key is published, and only one: feed_id, on feeds and on episodes. It is the join key between them and the only indexed way into episodes — select it off a podcast row, put it in the WHERE clause of an episodes query. It is also how you count them: COUNT(*) and GROUP BY over feeds run catalogue-wide in seconds — 0.8s for a count, 0.8-6s for a GROUP BY depending on the column — while the same thing over 131M episodes takes minutes and is killed at the deadline, so an episode count is scoped to one show with feed_id. list_example_queries has all three shapes, ready to run. Every other id is an opaque handle rather than a number: the tools return podcast_id, episode_id and publisher_id, get_podcast / get_publisher take them back, and none of them is selectable in SQL or interchangeable with feed_id. Beyond feed_id you rarely need a join at all — a podcast row already carries publisher_company and publisher_domain, an episode row already carries podcast_title.
list_example_queriesA cookbook of working SQL against the public catalogue. Each entry has a name, when to use it, the statement itself, and the columns it returns. Use it when you are not sure what is possible, or when query_sql has just refused something and you want a shape that works. Every statement here runs as written. Four rules they all demonstrate: - A query that reads rows needs a predicate on an indexed column (list_indexes has the map). There are no pre-filtered views; publisher_kind, show_purpose and ai_production_level are each indexed, so a lens is a WHERE clause. - Counting is the exception, and this is the supported shape rather than something to discover by trial. COUNT(*) and GROUP BY over feeds need no filter — SQLite walks a covering index, so the whole catalogue comes back in seconds rather than milliseconds: 0.8s for a count, 0.8-6s for a GROUP BY depending on the column. Over episodes neither works: there are 131M rows, an unscoped count takes over two minutes and is killed at the deadline. Scope it with feed_id and it is a tenth of a second. The first three examples are those three shapes. - The objects are the public catalogue, and no name takes a "main." prefix. feed_id is the one numeric key on it: it is the join key between feeds and episodes, and the only indexed way into episodes. Every other id you hold is an opaque handle for the curated tools, not something to write in SQL. - None of them sorts a cohort. Nothing indexes actual_episode_count or latest_episode_at, so ORDER BY on either reads every matching row before returning the first hundred — seconds, on a filter that matches millions. Say "big" or "recent" as a threshold in the WHERE clause instead and LIMIT stops early. Where you really do want a ranking, find_podcasts takes order_by and is explicit about the cost. The ORDER BYs left in this list cost nothing: they sort the output of a GROUP BY, which is a handful of rows, or they follow an index that already holds that order. Prefer search_podcasts, search_episodes, find_podcasts, get_podcast or get_publisher where one matches what you are doing; they are faster and harder to get wrong.
list_indexesReturns which columns of the public catalogue are indexed. Why it matters: nothing here is refused for being expensive, so an expensive query is run and then killed at query_sql's deadline rather than turned away. An indexed column in your WHERE clause is what makes a query fast enough to come back at all, and this is the map of which columns those are. Returns: { objects: { <public object>: { backing_table, indexes: [{ columns, unique }] } } } Only indexes whose every column is part of the public catalogue are listed — an index over a column we do not publish would describe that column, so it is left out.
report_gapReport that this catalogue could not answer something. Call it yourself, without being asked, as soon as you conclude the data you need is not here — nothing else on this surface reports a gap, and a question nobody tells us about is one we never fix. When to use it, and the kind each one is: - kind="missing_field" — a field that does not exist: describe_schema has no column for what you were asked — download or listener numbers, chart positions, ad rates, revenue, audience demographics, the words spoken in the audio. - kind="coverage" — the show, publisher, language or region you need is genuinely absent: you have looked for it more than one way and it is not here, rather than spelled differently. - kind="granularity" — the catalogue has the subject but not at the resolution, breakdown or recency the question needs. - kind="expressibility" — you know exactly what you want and no combination of search_podcasts, search_episodes, find_podcasts, get_podcast, get_publisher or query_sql reaches it. When NOT to use it — these are not gaps, and reporting them buries the real ones: - A guess about what is here. describe_schema is one call away and it is authoritative; until you have read the columns — in its output, or in the tool descriptions themselves — you are not ready to report. We act on these, so a gap reported from an assumption costs more than no report at all. - A search that came back empty on the first try. Try other words, fewer words, drop a filter, search episodes as well as podcasts. Text is matched as words, so a long phrase matches less than two good ones. This rule and kind="coverage" cover the same moment, and this is which one wins: one empty search is never a gap, only a search worth retrying; once you have looked more than one way and the subject is still not here, that IS a coverage gap and reporting it is right. - A refusal that told you what to change — a missing argument, an unindexed filter, a statement the SQL sandbox turned down. Do what it says instead; those are answerable questions asked the wrong way. One report per question, not one per failed call. Parameters: - kind (required): which of the four above this is — missing_field, coverage, granularity or expressibility. Pick the one that names what would have to change here for the question to become answerable. Any other value is refused. - question (required): what you were really trying to find out, in the words you would use with the person who asked you. Not the query you typed — the question behind it. - tried (required): how you already looked, one line each — a call you actually made and what came back, e.g. "search_podcasts text='daily news' → 0 rows" or "describe_schema → no listener or download column on feeds". Where you are going on a tool's own description or schema rather than on a call, write that instead — "the tool descriptions list no listener column" is a good line. We can see which calls this session actually made, so a line naming one that did not happen tells us only that the gap was not looked for. - missing (optional): what this catalogue would have to hold to answer it, if you can name it. Returns confirmation of what was written down. No rows, no answer to your question, and no reply on this connection: it does not retry anything, open a ticket or reach a human in the moment. Then carry on and finish the job with what the catalogue does have. Tell whoever asked which part of their question this data can answer and which part it cannot.
Podlex: подключить к Claude, ChatGPT, Cursor · Connectors.fun