Voice
Castrecall
CastRecall β turn podcast listening into retrievable memory. An OpenClaw plugin that ingests listened episodes, finds or generates transcripts, and creates approval-gated memory candidates.
Install
npm install &&
README
# CastRecall
Turn podcast listening into retrievable memory.
CastRecall is an open-source [OpenClaw](https://openclaw.ai) tool plugin that watches what you listen to, finds or generates the episode transcript, and stores it as **private, provenance-bearing source material**. Useful excerpts are surfaced as **approval-gated review candidates** β nothing is ever silently promoted into durable memory.
The first question it answers: **"What have I been absorbing lately, and how is it shaping my thinking?"**
## MVP scope
v0 is **Pocket Casts only** and **read-only**:
- Syncs your Pocket Casts listening history (never mutates playback state β no play/pause/star/seek tools exist).
- Resolves each listen to its canonical RSS feed item.
- Walks a cost-aware transcript ladder (see below).
- Stores full transcripts privately with a provenance sidecar.
- Generates markdown review candidates for human approval.
## β οΈ The Pocket Casts caveat
**Pocket Casts has no official public API.** CastRecall uses the same reverse-engineered web-player endpoints as community tools such as [essoen/PocketCasts-mcp](https://github.com/essoen/PocketCasts-mcp) (prior art for this plugin). That means:
- It can break or be blocked by Pocket Casts at any time, without notice.
- It needs your account email and password (env vars, read-only requests only). Accounts created via *Sign in with Google/Apple* have no password and won't work.
- If Pocket Casts ever ships an official API or export, CastRecall will move to it.
Use it with those expectations.
## Privacy model
- **Full transcripts are source material, not memory.** They live under CastRecall's private data dir with a `provenance.json` sidecar (`privacyClass: "private-source"`).
- **CastRecall never writes to durable OpenClaw memory.** It generates review candidates in `review/pending/`; a human decides what graduates β ideally rephrased in your own words.
- **Credentials are env-only** and never logged, stored, echoed in errors, or passed through plugin config.
- Transcripts of published podcasts can still be copyrighted material β keeping them as private source data (rather than republishing or promoting them wholesale) is the intended use.
## Install
```bash
# from GitHub
openclaw plugins install https://github.com/comamitc/castrecall
# or from a local clone (for development)
git clone https://github.com/comamitc/castrecall
cd castrecall && npm install && npm run plugin:build
openclaw plugins install --link .
```
Then enable it if needed with `openclaw plugins enable castrecall`.
## First-run setup
1. Set your Pocket Casts credentials in the environment OpenClaw runs in:
```bash
export POCKETCASTS_EMAIL="[email protected]"
export POCKETCASTS_PASSWORD="..."
```
(See `.env.example` for every variable.)
2. Optionally configure transcript providers (Taddy, STT β see below).
3. Ask your agent to run `castrecall_setup_status`. It reports what is and isn't configured β without ever printing secrets β plus data-dir location and counts.
## Tools
| Tool | What it does |
| --- | --- |
| `castrecall_setup_status` | Setup/health report: configured providers, ladder availability, counts. Run first. |
| `castrecall_sync_history` | Read-only Pocket Casts history sync; records new listens idempotently. |
| `castrecall_recent` | Lists synced listens with transcript status and episode UUIDs. |
| `castrecall_fetch_transcript` | Runs the transcript ladder for one episode; stores transcript + provenance. |
| `castrecall_generate_review` | Writes approval-gated review candidates for stored transcripts. |
## The transcript ladder
Cheapest and most open first; every rung reports why it hit, missed, or was skipped:
1. **RSS `<podcast:transcript>`** (always on, free) β the open [podcast namespace](https://podcastindex.org/namespace/1.0) standard. Supports plain text, HTML, VTT, SRT, and JSON transcripts, normalized to clean text with speaker labels where available.
2. **Taddy** (optional) β set `TADDY_API_KEY` + `TADDY_USER_ID` ([free signup](https://taddy.org/developers); transcript access needs a paid Taddy plan).
3. **Speech-to-text** (optional, **costs money**, disabled by default) β enable explicitly with `CASTRECALL_ENABLE_STT=true`. Providers: **AssemblyAI** (default; transcribes straight from the audio URL) or **OpenAI** (`gpt-4o-transcribe`; requires downloading and uploading the audio, 25 MB API limit).
If no rung produces a transcript, the episode is marked `failed` with the per-rung reasons β no fake output, ever.
## Environment variables
| Variable | Required | Purpose |
| --- | --- | --- |
| `POCKETCASTS_EMAIL` / `POCKETCASTS_PASSWORD` | for sync | Read-only history access (unofficial API). |
| `CASTRECALL_DATA_DIR` | no | Data dir (default `~/.openclaw/castrecall`). |
| `CASTRECALL_HISTORY_LIMIT` | no | Max entries per sync (default 100). |
| `TADDY_API_KEY` / `TADDY_USER_ID` | no | Enables the Taddy ladder rung. |
| `CASTRECALL_ENABLE_STT` | no | `true` to allow paid STT fallback. |
| `CASTRECALL_STT_PROVIDER` | no | `assemblyai` (default) or `openai`. |
| `ASSEMBLYAI_API_KEY` | with STT | AssemblyAI transcription. |
| `OPENAI_API_KEY` | with STT | OpenAI transcription. |
| `CASTRECALL_OPENAI_STT_MODEL` | no | Default `gpt-4o-transcribe`. |
Non-secret settings (`dataDir`, `historyLimit`, `sttEnabled`, `sttProvider`) can also be set via the plugin's config schema; env vars win when both are set.
## Data layout
```
~/.openclaw/castrecall/
βββ state.json # sync state: seen listens, transcript status
βββ sources/<episodeUuid>/ # private source material
β βββ raw.<ext> # transcript exactly as fetched/generated
β βββ transcript.txt # normalized plain text
β βββ provenance.json # platform, feed, URLs, timestamps, source, privacy class
βββ review/pending/<episodeUuid>.md # approval-gated review candidates
```
## Example workflow
> **You:** "Sync my podcast listens and prep reviews for anything new."
>
> **Agent:** runs `castrecall_sync_history` β 3 new listens. Runs `castrecall_fetch_transcript` for each (2 via RSS transcripts, 1 has none and STT is off). Runs `castrecall_generate_review` β 2 candidates in `review/pending/`.
>
> **You:** read the candidates, keep one durable idea in your own words, delete the rest.
## Troubleshooting
- **"Pocket Casts credentials are not configured"** β set `POCKETCASTS_EMAIL` / `POCKETCASTS_PASSWORD` in the environment OpenClaw runs in (not just your shell).
- **"Pocket Casts rejected the configured credentials"** β check them; Google/Apple-SSO accounts cannot be used (no password exists).
- **Login worked before but fails now** β the unofficial API may have changed or rate-limited you; wait and retry, and check the repo's issues.
- **"no-transcript" with all rungs missed/skipped** β the feed declares no transcript and no optional provider is configured. Configure Taddy, or enable STT for that episode's fetch.
- **STT skipped even with a key set** β STT must be explicitly enabled (`CASTRECALL_ENABLE_STT=true`); it costs money per episode.
- **OpenAI STT fails on long episodes** β the 25 MB upload limit; use `CASTRECALL_STT_PROVIDER=assemblyai`.
- **Where did my data go?** β `castrecall_setup_status` prints the data dir.
## Development
```bash
npm install
npm run typecheck # tsc --noEmit
npm test # vitest (35 tests: parsing, normalization, storage idempotency, error paths)
npm run plugin:build # tsc + openclaw plugins build (regenerates openclaw.plugin.json)
npm run plugin:validate # openclaw plugins validate
```
Architecture notes live in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
## License
[MIT](LICENSE)
voice
Comments
Sign in to leave a comment