Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
d6189af
Keep clip segments in sync when a suggestion's range is edited
nmbrthirteen Oct 3, 2026
4bf3fca
Fix SRT timestamp rounding so milliseconds never overflow to 1000
nmbrthirteen Oct 3, 2026
fe31f12
Fix NTSC timecode: honor drop-frame and 1001/1000 pulldown rate
nmbrthirteen Oct 3, 2026
670cff7
Salt the signal cache key with an analyzer version
nmbrthirteen Oct 3, 2026
af4a460
Fix whisper.cpp English-only decoding and provision medium/large mode…
nmbrthirteen Oct 3, 2026
bfa0012
Invalidate session transcript when the working video changes
nmbrthirteen Oct 3, 2026
9b34029
Detect sentence openers in caseless scripts like Georgian
nmbrthirteen Oct 3, 2026
d3777cb
Fix PodStack command wiring and give install-aware studio start hints
nmbrthirteen Oct 3, 2026
d1d31d4
Key preview stills by sync basis so a nudge invalidates them
nmbrthirteen Oct 3, 2026
d950e24
Make get_ui_state work when the Web UI is not running
nmbrthirteen Oct 3, 2026
3b9ab0c
Use medians, not means, for performance-learnings buckets
nmbrthirteen Oct 3, 2026
a9245e5
Strip ASS override tags on SRT/VTT import and escape control characte…
nmbrthirteen Oct 3, 2026
5f2f78d
Merge multi-word corrections across consecutive caption words
nmbrthirteen Oct 3, 2026
7f40ce6
Fix transcript cache misses from unresolved engine and widen the cach…
nmbrthirteen Oct 3, 2026
f8487c0
Add a review sync status for fits that look clean but may be wrong
nmbrthirteen Oct 3, 2026
442b740
CI: install ffmpeg for Python tests, exclude dist from vitest, add re…
nmbrthirteen Oct 3, 2026
6273869
Fix silence removal dropping zero-duration words and stitching across…
nmbrthirteen Oct 3, 2026
32a7506
Add docs/limitations.md stating what each stage can and cannot do
nmbrthirteen Oct 3, 2026
b12cf66
Bound clip ranges to source duration and verify renders before report…
nmbrthirteen Oct 3, 2026
6628431
Detect sources that changed on disk and force a re-sync
nmbrthirteen Oct 3, 2026
ee87544
Thread a real language through parsed transcripts and fix speaker_seg…
nmbrthirteen Oct 3, 2026
6c76c74
Update podcli-installed PodStack commands on upgrade, keep user edits
nmbrthirteen Oct 3, 2026
4910272
Replace whisper.cpp voice-snap's index matrix with an O(n) running sum
nmbrthirteen Oct 3, 2026
d80155e
Time multi-segment clip captions from each part's probed duration
nmbrthirteen Oct 3, 2026
9663ec0
Refuse a cloud pull against a moved timeline and keep removal reasons
nmbrthirteen Oct 3, 2026
7b38e6f
Publish a render's video, stems and record atomically
nmbrthirteen Oct 3, 2026
580abb1
Give Codex the same MCP and PodStack install path as Claude
nmbrthirteen Oct 3, 2026
de0920a
Warn when a source's frame rate looks variable or had to be guessed
nmbrthirteen Oct 3, 2026
46adf13
Add sample-mode transcription: test a language on a short window first
nmbrthirteen Oct 3, 2026
47670c4
Skip case transforms for caseless scripts like Georgian in captions a…
nmbrthirteen Oct 3, 2026
0639bfd
Make podcli doctor actually run checks instead of only printing paths
nmbrthirteen Oct 3, 2026
c51f14a
Support selecting which audio stream a source uses
nmbrthirteen Oct 3, 2026
f594cd6
Flag a selected clip as changed when it is edited after approval
nmbrthirteen Oct 3, 2026
41a5a54
Add engine comparison report: transcribe a sample with two engines, d…
nmbrthirteen Oct 3, 2026
0211974
Warn when the caption font is missing glyphs instead of rendering sil…
nmbrthirteen Oct 3, 2026
3725f2c
Ground thumbnail headline copy in the clip, add Georgian font coverage
nmbrthirteen Oct 3, 2026
11e12eb
Split shots on drifting cameras so no piece slips more than half a frame
nmbrthirteen Oct 3, 2026
68ab72e
Add per-episode decisions, keyed by video identity, with open questions
nmbrthirteen Oct 3, 2026
501f1b9
Write SRT/VTT sidecars and an optional caption-free clean variant per…
nmbrthirteen Oct 3, 2026
32d480d
Cache rendered shots and validate every render's frames, decode and l…
nmbrthirteen Oct 3, 2026
a31f26b
Normalize the mix in two passes, high-pass each mic, and correct drif…
nmbrthirteen Oct 3, 2026
2a8e9e8
Add mine_channel: mine a YouTube channel's captions without downloadi…
nmbrthirteen Oct 3, 2026
82b3935
Fix release-hygiene.mjs tripping on its own secret-detection test fix…
nmbrthirteen Oct 3, 2026
dc7c925
Sync a file by hand from timeline and source anchor pairs
nmbrthirteen Oct 3, 2026
8db5560
Add per-camera input LUTs, look stills per camera, and a color handof…
nmbrthirteen Oct 3, 2026
01d2c5c
Add omnilingual ASR engine (sherpa-onnx) and resumable long transcrip…
nmbrthirteen Oct 3, 2026
3f296c5
Read look stills per camera in the nudge test
nmbrthirteen Oct 3, 2026
0e50be0
Fit cameras of another frame size inside the sequence in Premiere and…
nmbrthirteen Oct 3, 2026
3b03fc4
Lead each speech-onset cut in by 0.12 s through silence
nmbrthirteen Oct 3, 2026
8e9f31d
Merge transcription engines and per-episode sessions
nmbrthirteen Oct 3, 2026
839e755
Render an opening hook from inside the clip before the clip plays
nmbrthirteen Oct 3, 2026
bf0bcd8
Accept, validate and edit an opening hook in the MCP tools and studio
nmbrthirteen Oct 3, 2026
5fa231a
Merge clip pipeline fixes and opening hooks
nmbrthirteen Oct 3, 2026
61612b5
Merge branch 'fix/multicam' into integrate/pipeline-hardening
nmbrthirteen Oct 3, 2026
c05a080
Thread an AI-proposed opening hook through the CLI render paths
nmbrthirteen Oct 3, 2026
576d25b
Fix fresh multicam edits, rolling caption repeats and doctor wording
nmbrthirteen Oct 3, 2026
3b549c8
Block yt-dlp flag injection via mine_channel urls
nmbrthirteen Oct 3, 2026
ec7d477
Verify mine_channel mines the requested video, not a redirect target
nmbrthirteen Oct 3, 2026
97d4628
Pin channel listing to the videos tab, drop tab entries without an id
nmbrthirteen Oct 3, 2026
a752c4a
Serialize episode decision writes, quarantine corrupt state, key deci…
nmbrthirteen Oct 3, 2026
c13d779
Stop adopting a pre-manifest user edit as the update baseline
nmbrthirteen Oct 3, 2026
bb36e13
Add a two-person thumbnail layout for interview clips
nmbrthirteen Oct 3, 2026
31d21ba
Escape every < in the engine comparison report, not just </script
nmbrthirteen Oct 3, 2026
b72f8e9
Keep transcriptVideoIdentity in sync with transcribe_start and new vi…
nmbrthirteen Oct 3, 2026
fb6a7d5
Merge branch 'feat/thumbnail-pair' into integrate/pipeline-hardening
nmbrthirteen Oct 3, 2026
539e292
Quote the server path in the Codex setup snippet
nmbrthirteen Oct 3, 2026
d87101e
Run the transcript/video identity guard when server.ts fills words fr…
nmbrthirteen Oct 3, 2026
b844ef5
Remove em dashes from comments added in this branch
nmbrthirteen Oct 3, 2026
3c0db62
Let modify_clip widen or shift a clip instead of pinning it to the ol…
nmbrthirteen Oct 3, 2026
0caa225
Keep 10ms words that a silence cut never touched
nmbrthirteen Oct 3, 2026
9a46f8e
Make MCP registration checks warnings, not FAIL, on a healthy install
nmbrthirteen Oct 3, 2026
2c39f6d
Stop release-hygiene from silently skipping non-ASCII filenames
nmbrthirteen Oct 3, 2026
5954f14
Carry trailing punctuation and other word fields through multi-word c…
nmbrthirteen Oct 3, 2026
3208501
Make record_decisions reject unknown fields instead of dropping them
nmbrthirteen Oct 3, 2026
40bcddd
Stop writing sidecars for captions-off renders and clear stale re-ren…
nmbrthirteen Oct 3, 2026
c6d59e6
Fix transcript cache key mismatches, diarization retry loop, and samp…
nmbrthirteen Oct 3, 2026
2dc8f6d
Clear a bad AssemblyAI receipt instead of retrying it forever
nmbrthirteen Oct 3, 2026
fb158ca
Use float64 for the voice-snap running sum on long files
nmbrthirteen Oct 3, 2026
b1d3ab4
Only require an audio stream in the output when the source has one
nmbrthirteen Oct 3, 2026
9a8f726
Count server.registerTool( registrations in the docs manifest too
nmbrthirteen Oct 3, 2026
f5b64e3
Treat a 0/0 file identity as unknown, not changed, and backfill it on…
nmbrthirteen Oct 3, 2026
ed743f1
Share one fallback decision between resolve_engine_info and transcrib…
nmbrthirteen Oct 3, 2026
1af757e
Only fail verify_full_decode on a real decode failure, not any stderr…
nmbrthirteen Oct 3, 2026
eb4b2a3
Refresh every probe field and the views built from it when a source c…
nmbrthirteen Oct 3, 2026
3dc14f0
Report duration as content length again, not the file including intro…
nmbrthirteen Oct 3, 2026
0b82d4b
Merge branch 'fix/review-security' into integrate/pipeline-hardening
nmbrthirteen Oct 3, 2026
f551241
Stop importing whisper/torch on every engine resolution
nmbrthirteen Oct 3, 2026
b94dfb7
Fold the omnilingual model file and window constants into the receipt…
nmbrthirteen Oct 3, 2026
a5b716b
Dedupe omnilingual words that land on both sides of a window seam
nmbrthirteen Oct 3, 2026
5187842
Catch up stale sources when a session is opened by id, not only by fo…
nmbrthirteen Oct 3, 2026
8c31495
Flag changedSinceSelection and recompute duration in the studio sugge…
nmbrthirteen Oct 3, 2026
b3039ac
Freeze the cloud push basis against what was sent, not what lands later
nmbrthirteen Oct 3, 2026
7b9c579
Keep the session when a persisted video is missing at startup, flag i…
nmbrthirteen Oct 3, 2026
982b9c1
Honor audio_stream_index in the mix, the stems, and both editor timel…
nmbrthirteen Oct 3, 2026
ede9198
Thread model and language into the CLI's direct transcribe cache lookups
nmbrthirteen Oct 3, 2026
8674c7b
Broadcast the cleared transcript and suggestions on a bare video change
nmbrthirteen Oct 3, 2026
8b082b1
Accept '.' as a non-drop timecode separator again
nmbrthirteen Oct 3, 2026
ca87efe
Send the transcript in the same request as a video change, not a seco…
nmbrthirteen Oct 3, 2026
a24c73e
Decide NTSC pulldown from the exact r_frame_rate, not the measured av…
nmbrthirteen Oct 3, 2026
801226a
Judge a sync fit's review flag on the inlier residual, not the outlie…
nmbrthirteen Oct 3, 2026
c287763
Remove em dashes from new comments and docstrings
nmbrthirteen Oct 3, 2026
d153e8b
Request subtitles explicitly in opening-hook render tests
nmbrthirteen Oct 3, 2026
9897879
Merge branch 'fix/review-transcription' into integrate/pipeline-harde…
nmbrthirteen Oct 3, 2026
ab634bc
Use the 1B Omnilingual model and document its limits
nmbrthirteen Oct 3, 2026
010942d
Merge branch 'fix/review-clips' into integrate/pipeline-hardening
nmbrthirteen Oct 3, 2026
269ebdd
Publish a render into a fresh directory and switch to it in one write
nmbrthirteen Oct 3, 2026
3ab4f89
Keep export results, offer Omnilingual in the studio, store partial r…
nmbrthirteen Oct 3, 2026
ed7dfcd
Measure the loudness gain on the kept audio, not the removed stretches
nmbrthirteen Oct 3, 2026
4fcc901
Check an input LUT exists at render and preview start, naming the camera
nmbrthirteen Oct 3, 2026
46213d7
Sample the decode check by default instead of decoding the whole episode
nmbrthirteen Oct 3, 2026
15881fa
Delete superseded preview stills instead of leaving one more per nudge
nmbrthirteen Oct 3, 2026
b7d546b
Only render look stills for cameras actually used in the cut
nmbrthirteen Oct 3, 2026
2015b7d
Merge branch 'fix/review-multicam' into integrate/pipeline-hardening
nmbrthirteen Oct 3, 2026
cb8b8e5
Revert "Publish a render into a fresh directory and switch to it in o…
nmbrthirteen Oct 3, 2026
550eae5
Keep stable multicam output paths and clear dropped stems
nmbrthirteen Oct 3, 2026
a704c3c
Drop em and en dashes from new comments and copy
nmbrthirteen Oct 3, 2026
59a00c5
Fetch the Omnilingual model only into podcli's own folder
nmbrthirteen Oct 3, 2026
c24f9f7
Merge branch 'fix/no-dashes' into integrate/pipeline-hardening
nmbrthirteen Oct 3, 2026
5351a02
Fix the strict decisions schema for zod 4 and three platform test gaps
nmbrthirteen Oct 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .claude/commands/auto.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: One-verb pipeline — drop a video, confirm strategy, render clips
allowed-tools: Read, Bash, mcp__podcli__transcribe_podcast, mcp__podcli__transcribe_start, mcp__podcli__transcribe_status, mcp__podcli__get_ui_state, mcp__podcli__set_video, mcp__podcli__suggest_clips, mcp__podcli__batch_create_clips, mcp__podcli__knowledge_base, mcp__podcli__clip_history
allowed-tools: Read, Bash, mcp__podcli__transcribe_podcast, mcp__podcli__transcribe_start, mcp__podcli__job_status, mcp__podcli__get_ui_state, mcp__podcli__set_video, mcp__podcli__suggest_clips, mcp__podcli__batch_create_clips, mcp__podcli__knowledge_base, mcp__podcli__clip_history, mcp__podcli__record_decisions
argument-hint: [video-path-or-episode-slug] [optional: count e.g. "5 clips"]
triggers:
- auto
Expand All @@ -21,7 +21,7 @@ This command orchestrates the existing MCP tools on top of the compact packed tr

1. **Read, don't watch.** Reason about clips from the packed markdown view — not raw segments, not frame dumps.
2. **Strategy first, render after.** Propose the cut list and WAIT for user confirmation before calling `batch_create_clips`.
3. **Knowledge base is context, not template.** If `` exists, read it for brand voice and format preferences. If not, infer from the content itself.
3. **Knowledge base is context, not template.** If `.podcli/knowledge/` exists, read it for brand voice and format preferences. If not, infer from the content itself.
4. **Never silently render.** Every clip that ships must appear in the proposal the user approved.
5. **Every clip carries its own context.** A stranger who never heard the episode has to follow it from the first second. If the moment is an answer, the question comes with it.

Expand All @@ -46,14 +46,16 @@ This command orchestrates the existing MCP tools on top of the compact packed tr
- Call `transcribe_start(file_path)` → returns `{job_id, cached, estimate}` immediately.
- If `cached: true`, skip to step 3.
- Otherwise emit a short status to the user: _"Transcription started — estimated {estimate}. I'll check progress every 30s."_
- Loop: call `transcribe_status(job_id, wait_seconds: 30)`. Between calls, emit ONE terse line to the user like `"Progress: 47% — pyannote diarization"`. Keep it to one line per poll — no repeat prose. Exit the loop when `done: true`.
- Loop: call `job_status(job_id, wait_seconds: 30)`. Between calls, emit ONE terse line to the user like `"Progress: 47%, pyannote diarization"`. Keep it to one line per poll, no repeat prose. Exit the loop when `done: true`.
- If `status: "error"`, stop and report the error.
3. Read the packed transcript: `get_ui_state(include_transcript: true)`. This returns a compact phrase-grouped view with speakers, silence gaps, and energy peaks.
- **If the header says speakers: 0**, stop and tell the user before going further. Without speaker labels you cannot tell a question from an answer, so the whole question-with-the-answer rule below is inert and the picks will be worse. Offer to re-transcribe with `transcribe_start(file_path, enable_diarization: true)`. Only continue without it if the user says to.
4. If `` exists, read `01-brand-identity.md`, `02-voice-and-tone.md`, and `04-shorts-creation-guide.md` for show context. Skip silently if missing — `/auto` works on any content.
4. If `.podcli/knowledge/` exists, read `01-brand-identity.md`, `02-voice-and-tone.md`, and `04-shorts-creation-guide.md` for show context. Skip silently if missing: `/auto` works on any content.
5. Call `clip_history` to see what's already been shipped for this episode. Avoid duplicates in the proposal.

**Fallback**: if `transcribe_start` returns an error about the Web UI not running, tell the user and offer either (a) run `npm run ui` in another terminal then retry, or (b) fall back to the synchronous `transcribe_podcast` (no live progress, works silently).
**Fallback**: if `transcribe_start` returns an error about the Web UI not running, tell the user and offer either (a) start the Web UI in another terminal then retry (`podcli studio` for a launcher install, `npm run ui` in a source checkout), or (b) fall back to the synchronous `transcribe_podcast` (no live progress, works silently).

6. **Ask once, reuse the answer.** `get_ui_state` lists this episode's unanswered decisions under `OPEN QUESTIONS` (clip count, duration range, captions, language, thumbnails, delivery target). Ask whichever are relevant to this run, batched, not one dialog box per field, then call `record_decisions(video_path, ...)` with the answers. On every later run against this same video, those fields are already answered and won't appear in `OPEN QUESTIONS` again.

### Phase 2 — Topic Map (silent)

Expand Down Expand Up @@ -86,6 +88,7 @@ Work inside one topic at a time. Set boundaries by meaning, not by the clock.
- The question has to be inside the clip. `context_line` is a note for the editor, not a fix: nothing burns it into the video yet, so a clip that relies on it still ships with no setup.
- If the question rambles past roughly 8 seconds, use `segments` to keep the asked part and cut the rambling, or drop the moment.
- Never open on a word pointing back before the cut: "that", "it", "they", "yeah", "so", "exactly", "right", "which is why". Widen the start until the reference is inside the clip.
- If the sharpest line sits mid-clip, you may pass it as `hook` (`{start, end, mode}`, 1-15 seconds) so it plays first. It must be a line actually spoken inside the clip, never invented text. `repeat` replays it in place; `move` lifts it out.

**end_second**

Expand Down
2 changes: 1 addition & 1 deletion .claude/commands/bootstrap-knowledge.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ triggers:

## Before starting

1. If `` has no files, run `podcli knowledge init` first so all 14 templates exist.
1. If `.podcli/knowledge/` has no files, run `podcli knowledge init` first so all 14 templates exist.
2. Ask for whichever of these the user has not provided:
- Channel or podcast URL (YouTube channel, Spotify show, RSS feed)
- Or a few sentences about the show if nothing is published yet
Expand Down
2 changes: 1 addition & 1 deletion .claude/commands/generate-titles.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Generate 8 verified title options for a clip, moment, or episode
allowed-tools: Read
allowed-tools: Read, mcp__podcli__knowledge_base
argument-hint: [clip-transcript-or-moment-brief]
triggers:
- titles for
Expand Down
2 changes: 1 addition & 1 deletion .claude/commands/plan-episode.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Design questions, story arc, and moment map BEFORE recording an episode
allowed-tools: Read, Write
allowed-tools: Read, Write, mcp__podcli__knowledge_base
argument-hint: [guest-name-and-company]
triggers:
- plan episode
Expand Down
2 changes: 2 additions & 0 deletions .claude/commands/plan-thumbnails.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ What is the single most compelling image or concept?
- Guest photo requirements
- Background suggestion
- Special visual elements
- **Layout:** `single` (one face) or `pair` (two people). Propose `pair` for interview clips where the exchange is the point: a question and its answer, a disagreement, a reaction. podcli takes both faces from the clip itself, guest on the left and host on the right. Set it with `manage_thumbnail_config` (`set_layout`), the "Two people" toggle on the clip page, or `podcli thumbnails --layout pair`. Add `--swap` to flip sides, or `--left-image` and `--right-image` to name the people. It falls back to `single` when podcli cannot tell two people apart, so keep a single-face brief ready.

### Step 4: Quality Check
- [ ] Readable at phone screen size
Expand All @@ -88,6 +89,7 @@ What is the single most compelling image or concept?

**Shorts (9:16):**
- Text: "[LINE 1] / [LINE 2 — accent]"
- Layout: [single / pair: guest left, host right]
- Visual: [action shot / dramatic imagery / B-roll]
- Text position: Lower third, centered

Expand Down
5 changes: 4 additions & 1 deletion .claude/commands/process-transcript.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Extract, score, and classify the best moments from a raw podcast transcript
allowed-tools: Read, Write
allowed-tools: Read, Write, mcp__podcli__knowledge_base
argument-hint: [transcript-file-or-paste]
triggers:
- transcript
Expand Down Expand Up @@ -96,6 +96,8 @@ Before scoring, fix each flagged moment's edges and state its payoff.

**Then run the standalone check.** Name what the viewer must already know. If it is anything other than nothing, the start moves back until the clip covers it. If it cannot, drop the moment.

**Optionally mark an opening hook.** If the sharpest line sits mid-clip, it can play first as a `hook` (1-15 seconds, `repeat` replays it in place, `move` lifts it out). It must be a line actually spoken inside the clip, quoted verbatim with its timestamps. Never invent hook text.

### Phase 4: Score Each Moment

For every flagged moment, score on four dimensions (1-5 each):
Expand Down Expand Up @@ -182,6 +184,7 @@ Format: comma-separated, under 500 characters.
**Payoff:** [What the viewer walks away with. One sentence, second person.]
**Needs:** [nothing | what the viewer must already know]
**Setup line:** [The question this answers, in one line, or omit when the clip carries its own setup]
**Opening hook:** [Optional. "Verbatim line" XX:XX-XX:XX, repeat or move. Omit when the clip opens strong on its own]

**Why it works:** [One sentence explaining the appeal]

Expand Down
6 changes: 5 additions & 1 deletion .claude/commands/produce-shorts.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Full pipeline from transcript to publish-ready content package
allowed-tools: Read, Write, Edit, Task
allowed-tools: Read, Write, Edit, Task, mcp__podcli__knowledge_base, mcp__podcli__get_ui_state, mcp__podcli__record_decisions
argument-hint: [transcript-file-or-episode-number]
triggers:
- process episode
Expand Down Expand Up @@ -29,6 +29,8 @@ Read the full knowledge base with the `knowledge_base` MCP tool:
- `07-thumbnail-guide.md` — visual specs
- `13-learnings.md` — past retro patterns (what worked, what didn't)

If a video is already set (`get_ui_state`), check its `OPEN QUESTIONS` block for unanswered episode decisions (clip count, duration range, captions, language, thumbnails, delivery target). Ask whichever are relevant to this run, batched into one NEEDS_INPUT prompt rather than one per field, then call `record_decisions(video_path, ...)` so the next run against this video doesn't ask again.

---

## Inputs
Expand All @@ -52,6 +54,8 @@ Each phase calls the corresponding skill's logic. Each phase reports its own Com

Extract guest info, flag 15-20 moments, anchor each one (boundaries by meaning, question pulled in or carried as a setup line, payoff written before any title), score them, select top moments, classify by content type, check for duplicates.

A moment may open with a `hook`: a 1-15 second line spoken inside the clip, played first. Quote it from the transcript. Never invent it.

### Phase 2: Title Development
*Runs `/generate-titles` logic per moment*

Expand Down
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@ jobs:
- run: node scripts/gen-docs-manifest.mjs
- run: node scripts/check-docs-drift.mjs

release-hygiene:
name: Release hygiene check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "20"
- run: node scripts/release-hygiene.mjs

python:
name: Python tests
runs-on: ${{ matrix.os }}
Expand All @@ -102,6 +114,17 @@ jobs:
with:
python-version: "3.12"
cache: "pip"
- name: Install ffmpeg
# Without this, every test that shells out to ffmpeg/ffprobe skips.
# About 22 tests were silently not running on any OS.
shell: bash
run: |
case "${{ runner.os }}" in
Linux) sudo apt-get update -qq && sudo apt-get install -y -qq ffmpeg ;;
macOS) brew install --quiet ffmpeg ;;
Windows) choco install ffmpeg -y --no-progress ;;
esac
ffmpeg -version | head -1
- name: Install minimal test deps
# Skip whisper/torch — tests don't exercise them and they balloon CI time.
run: |
Expand Down
17 changes: 17 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# AGENTS.md

This file exists for coding agents (OpenAI Codex, opencode, Aider, Cursor Agent,
and others) that read `AGENTS.md` by convention.

- `CLAUDE.md` is the primary instruction document: project layout, the MCP tool
table, the knowledge base, and the quality gate all live there and are not
repeated here.
- `AGENTS.podstack.md` covers cross-tool PodStack usage: how each host runs the
content-production commands (`/plan-episode`, `/process-transcript`,
`/generate-titles`, and the rest), and where each host installs them.
- `.claude/commands/*.md` are the PodStack command sources. Claude Code reads
them directly from that path; `podcli auto` (and the other PodStack
commands) also installs them as Codex skills under `~/.codex/skills/` when
the `codex` CLI is present.

Start with `CLAUDE.md`, then `AGENTS.podstack.md` for command-by-command detail.
28 changes: 14 additions & 14 deletions AGENTS.podstack.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ PodStack turns your AI tool into a podcast content team: Episode Architect, Cont

## How to use

Each skill below is a self-contained instruction file in `commands/` (or `.claude/commands/`, `.codex/prompts/`, `.cursor/rules/`, `.opencode/commands/`, depending on which host installed it).
Each skill below is a self-contained instruction file in `commands/` (or `.claude/commands/`, `~/.codex/skills/<name>/SKILL.md`, `.cursor/rules/`, `.opencode/commands/`, depending on which host installed it).

**To run a skill:** ask your agent to "run the [skill-name] skill" or invoke its slash command (`/[skill-name]`) where supported. The agent opens the corresponding file and follows it step by step.

Expand All @@ -30,7 +30,7 @@ Each skill below is a self-contained instruction file in `commands/` (or `.claud

- **role:** Episode Architect
- **description:** Design questions, story arc, and moment map BEFORE recording
- **allowed-tools:** Read, Write
- **allowed-tools:** Read, Write, mcp__podcli__knowledge_base
- **triggers:** plan episode, upcoming recording, guest prep, prepare for interview
- **outputs:** episode plan written to `episodes/ep[XX]-[guest]-plan.md`
- **next:** record → `/process-transcript`
Expand All @@ -39,7 +39,7 @@ Each skill below is a self-contained instruction file in `commands/` (or `.claud

- **role:** Content Analyst
- **description:** Extract, score, classify best moments from a raw transcript
- **allowed-tools:** Read, Write
- **allowed-tools:** Read, Write, mcp__podcli__knowledge_base
- **triggers:** transcript, process transcript, extract moments, podcast transcript
- **outputs:** moment brief with timestamps, scores, titles, thumbnails, descriptions
- **next:** `/generate-titles` or `/produce-shorts`
Expand All @@ -48,7 +48,7 @@ Each skill below is a self-contained instruction file in `commands/` (or `.claud

- **role:** Title Writer
- **description:** Generate 8 verified title options for a clip or moment
- **allowed-tools:** Read
- **allowed-tools:** Read, mcp__podcli__knowledge_base
- **triggers:** titles for, title options, write titles, generate titles
- **outputs:** 8 titles + 2 top picks with rationale

Expand Down Expand Up @@ -80,7 +80,7 @@ Each skill below is a self-contained instruction file in `commands/` (or `.claud

- **role:** Producer (master orchestrator)
- **description:** Full pipeline from transcript to publish-ready content package
- **allowed-tools:** Read, Write, Edit, Task
- **allowed-tools:** Read, Write, Edit, Task, mcp__podcli__knowledge_base
- **triggers:** process episode, produce shorts, full pipeline, prep episode, make content package
- **outputs:** complete content package in `episodes/ep[XX]-[guest]-content-package.md`
- **orchestrates:** process-transcript → generate-titles → generate-descriptions → plan-thumbnails → review-content
Expand Down Expand Up @@ -114,16 +114,16 @@ Skill files read the 14 knowledge files at `.podcli/knowledge/`; the full file t

PodStack ships one source-of-truth (`commands/`) and installs to the right location for each tool:

| Host | Install location | Primary doc |
|------|-----------------|-------------|
| Claude Code | `.claude/commands/*.md` | `CLAUDE.md` |
| OpenAI Codex | `.codex/prompts/*.md` | `AGENTS.podstack.md` (this file) |
| Cursor | `.cursor/rules/*.mdc` | `AGENTS.podstack.md` |
| opencode | `.opencode/commands/*.md` | `AGENTS.podstack.md` |
| Generic | `commands/*.md` | `AGENTS.podstack.md` |
| Host | Install location | Installed by | Primary doc |
|------|-----------------|--------------|-------------|
| Claude Code | `.claude/commands/*.md` (per project) | `podcli auto` / any PodStack command | `CLAUDE.md` |
| OpenAI Codex | `~/.codex/skills/<name>/SKILL.md` (global) | `podcli auto` / any PodStack command, when the `codex` CLI is on PATH | `AGENTS.podstack.md` (this file) |
| Cursor | `.cursor/rules/*.mdc` | not automated yet, copy by hand | `AGENTS.podstack.md` |
| opencode | `.opencode/commands/*.md` | not automated yet, copy by hand | `AGENTS.podstack.md` |
| Generic | `commands/*.md` | not automated yet, copy by hand | `AGENTS.podstack.md` |

These command files ship with podcli; place the set for your tool (left column) in
its command dir. See `README.md` for per-host usage examples.
Claude and Codex installs are automatic and kept in sync on upgrade; see `README.md`
for per-host usage examples and manual steps for the other hosts.

---

Expand Down
5 changes: 4 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Both share the same knowledge base at `.podcli/knowledge/`.

## MCP tools (podcli engine)

All 27 tools registered by the MCP server.
All 30 tools registered by the MCP server.

**Transcription and input**

Expand All @@ -43,6 +43,8 @@ All 27 tools registered by the MCP server.
| `set_video` | Set the working video without transcribing |
| `import_transcript` | Import an external transcript with word-level timestamps, skips Whisper |
| `parse_transcript` | Parse a speaker-labeled plain text transcript into word-level timestamps |
| `compare_transcription_engines` | Transcribe one sample with two engines and write a side-by-side disagreement report |
| `mine_channel` | List a YouTube channel's uploads or mine one video's existing captions, without downloading the video |

**Clip workflow**

Expand All @@ -56,6 +58,7 @@ All 27 tools registered by the MCP server.
| `batch_create_clips` | Render multiple clips in one batch |
| `manage_reel` | Build a highlights reel: detect once, edit moments, rebuild without re-detecting |
| `analyze_energy` | Analyze audio energy levels to find high-energy moments |
| `record_decisions` | Record per-episode decisions (clip count, duration range, captions, language, thumbnails, delivery target) so later runs never re-ask |

**Full-episode editing**

Expand Down
Loading
Loading