@thierrynakoa/fire-flow 12.2.1 → 13.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/CREDITS.md +25 -0
  2. package/DOMINION-FLOW-OVERVIEW.md +182 -38
  3. package/README.md +399 -455
  4. package/TROUBLESHOOTING.md +264 -264
  5. package/agents/fire-debugger.md +54 -0
  6. package/agents/fire-executor.md +1610 -1033
  7. package/agents/fire-fact-checker.md +1 -1
  8. package/agents/fire-planner.md +85 -17
  9. package/agents/fire-project-researcher.md +1 -1
  10. package/agents/fire-researcher.md +4 -22
  11. package/agents/{fire-phoenix-analyst.md → fire-resurrection-analyst.md} +394 -394
  12. package/agents/fire-reviewer.md +552 -499
  13. package/agents/fire-verifier.md +114 -19
  14. package/bin/cli.js +18 -101
  15. package/commands/fire-0-orient.md +2 -2
  16. package/commands/fire-1a-new.md +50 -15
  17. package/commands/fire-1c-setup.md +33 -5
  18. package/commands/fire-1d-discuss.md +87 -1
  19. package/commands/fire-2-plan.md +556 -527
  20. package/commands/fire-3-execute.md +2046 -1356
  21. package/commands/fire-4-verify.md +975 -906
  22. package/commands/fire-5-handoff.md +46 -5
  23. package/commands/fire-6-resume.md +2 -31
  24. package/commands/fire-add-new-skill.md +138 -19
  25. package/commands/fire-autonomous.md +14 -2
  26. package/commands/fire-complete-milestone.md +1 -1
  27. package/commands/fire-cost.md +179 -183
  28. package/commands/fire-debug.md +1 -6
  29. package/commands/fire-loop-resume.md +2 -2
  30. package/commands/fire-loop-stop.md +1 -1
  31. package/commands/fire-loop.md +2 -15
  32. package/commands/fire-map-codebase.md +1 -1
  33. package/commands/fire-migrate-database.md +548 -0
  34. package/commands/fire-new-milestone.md +1 -1
  35. package/commands/fire-reflect.md +1 -2
  36. package/commands/fire-research.md +142 -21
  37. package/commands/{fire-phoenix.md → fire-resurrect.md} +859 -603
  38. package/commands/fire-scaffold.md +297 -0
  39. package/commands/fire-search.md +1 -2
  40. package/commands/fire-security-scan.md +483 -484
  41. package/commands/fire-setup.md +359 -0
  42. package/commands/fire-skill.md +770 -0
  43. package/commands/fire-skills-diff.md +506 -506
  44. package/commands/fire-skills-history.md +388 -388
  45. package/commands/fire-skills-rollback.md +7 -7
  46. package/commands/fire-skills-sync.md +470 -470
  47. package/commands/fire-test.md +5 -5
  48. package/commands/fire-todos.md +1 -1
  49. package/commands/fire-update.md +5 -5
  50. package/commands/fire-validate-skills.md +282 -0
  51. package/commands/fire-vuln-scan.md +492 -493
  52. package/hooks/run-hook.sh +8 -8
  53. package/hooks/run-session-end.sh +7 -7
  54. package/hooks/session-end.sh +90 -90
  55. package/hooks/session-start.sh +1 -1
  56. package/package.json +4 -24
  57. package/plugin.json +7 -7
  58. package/references/autonomy-levels.md +235 -0
  59. package/references/behavioral-directives.md +95 -3
  60. package/references/blocker-tracking.md +1 -1
  61. package/references/circuit-breaker.md +93 -2
  62. package/references/context-engineering.md +227 -9
  63. package/references/honesty-protocols.md +70 -1
  64. package/references/issue-to-pr-pipeline.md +149 -150
  65. package/references/metrics-and-trends.md +1 -2
  66. package/references/research-improvements.md +4 -108
  67. package/references/sdlc-mapping.md +73 -0
  68. package/references/state-machine.md +151 -0
  69. package/skills-library/AVAILABLE_TOOLS_REFERENCE.md +333 -0
  70. package/skills-library/SKILLS-INDEX.md +57 -558
  71. package/skills-library/SKILLS_LIBRARY_INDEX.md +532 -0
  72. package/skills-library/_general/api-patterns/api-field-name-mismatch.md +107 -0
  73. package/skills-library/_general/api-patterns/streaming-command-timeout.md +122 -0
  74. package/skills-library/_general/api-patterns/streaming-proxy-cors-bypass.md +102 -0
  75. package/skills-library/_general/automation/settings-gui-generator.md +172 -0
  76. package/skills-library/_general/database-solutions/data-type-mapping-reference.md +181 -0
  77. package/skills-library/_general/database-solutions/mysql-limit-offset-string-coercion.md +102 -0
  78. package/skills-library/_general/database-solutions/mysql-to-pg-migration.md +195 -0
  79. package/skills-library/_general/database-solutions/orm-schema-portability.md +193 -0
  80. package/skills-library/_general/database-solutions/persistent-analysis-storage.md +207 -0
  81. package/skills-library/_general/database-solutions/pg-to-mysql-schema-migration-methodology.md +190 -0
  82. package/skills-library/_general/database-solutions/sql-dialect-compatibility-matrix.md +306 -0
  83. package/skills-library/_general/database-solutions/sqlite-to-pg-migration.md +219 -0
  84. package/skills-library/_general/frontend/canvas-bubble-animation-grouping.md +270 -0
  85. package/skills-library/_general/frontend/color-token-migration.md +112 -0
  86. package/skills-library/_general/frontend/framer-motion-layoutid-grouping.md +150 -0
  87. package/skills-library/_general/frontend/pyqt6-settings-dialog.md +191 -0
  88. package/skills-library/_general/frontend/react-flow-animated-layout-switching.md +101 -0
  89. package/skills-library/_general/frontend/react-hooks-order-debugging.md +141 -0
  90. package/skills-library/_general/frontend/redux-localstorage-auth-desync.md +126 -0
  91. package/skills-library/_general/frontend/safari-csp-theme-color-debugging.md +124 -0
  92. package/skills-library/_general/frontend/safari-sw-cache-poisoning.md +138 -0
  93. package/skills-library/_general/frontend/svg-sparkline-no-charting-library.md +131 -0
  94. package/skills-library/_general/growth-marketing/oss-daily-growth-intelligence.md +224 -0
  95. package/skills-library/_general/integrations/claude-code-local-mcp-integration.md +250 -0
  96. package/skills-library/_general/integrations/mcp-composite-tool-orchestration.md +200 -0
  97. package/skills-library/_general/methodology/AGENT_SDK_STANDALONE_TOOLING.md +181 -0
  98. package/skills-library/_general/methodology/AGENT_TEAMS_GUIDE.md +169 -0
  99. package/skills-library/_general/methodology/ALAS_STATEFUL_EXECUTION.md +207 -0
  100. package/skills-library/_general/methodology/AUTO_REVIEWER_SUBAGENT.md +211 -0
  101. package/skills-library/_general/methodology/CONSISTENCY_CHECK_AMBIGUITY_GATE.md +96 -0
  102. package/skills-library/_general/methodology/DEAD_ENDS_SHELF.md +4 -4
  103. package/skills-library/_general/methodology/DISTILL_NOT_DUMP.md +108 -0
  104. package/skills-library/_general/methodology/EXECUTION_PROGRESS_MONITOR.md +157 -0
  105. package/skills-library/_general/methodology/HIERARCHICAL_REVIEW_MARS.md +122 -0
  106. package/skills-library/_general/methodology/MCP_INTER_AGENT_BRIDGE.md +207 -0
  107. package/skills-library/_general/methodology/MERMAID_WIZARD_DIAGRAMS.md +77 -0
  108. package/skills-library/_general/methodology/MISSING_DIMENSION_DETECTOR.md +89 -0
  109. package/skills-library/_general/methodology/MULTI_AGENT_COORDINATION.md +397 -0
  110. package/skills-library/_general/methodology/OBSERVATION_MASKING.md +100 -0
  111. package/skills-library/_general/methodology/PHOENIX_REBUILD_METHODOLOGY.md +82 -11
  112. package/skills-library/_general/methodology/REVIEW_BACKTRACK_PANEL.md +140 -0
  113. package/skills-library/_general/methodology/REVIEW_FIX_LOOP.md +117 -0
  114. package/skills-library/_general/methodology/VOTING_VERDICT_ARBITRATION.md +155 -0
  115. package/skills-library/_general/methodology/ZERO_FRICTION_CLI_SETUP.md +2 -2
  116. package/skills-library/_general/methodology/dead-code-activation.md +123 -0
  117. package/skills-library/_general/methodology/debug-swarm-researcher-escape-hatch.md +240 -240
  118. package/skills-library/_general/methodology/shell-autonomous-loop-fixplan.md +1 -1
  119. package/skills-library/_general/patterns-standards/GOF_DESIGN_PATTERNS_FOR_AI_AGENTS.md +5 -5
  120. package/skills-library/_general/patterns-standards/cascading-failure-diagnosis.md +119 -0
  121. package/skills-library/_general/patterns-standards/domain-specific-layout-algorithms.md +209 -0
  122. package/skills-library/_general/patterns-standards/python-desktop-app-architecture.md +399 -0
  123. package/skills-library/_general/patterns-standards/realtime-monitoring-dashboard.md +457 -0
  124. package/skills-library/_general/patterns-standards/togglable-processing-pipeline.md +169 -0
  125. package/skills-library/_general/performance/liveclock-extraction.md +112 -0
  126. package/skills-library/_general/performance/ref-based-canvas-animation.md +117 -0
  127. package/skills-library/_general/performance/use-visible-interval.md +131 -0
  128. package/skills-library/_general/testing/playwright-firefox-withcredentials-auth-issue.md +104 -0
  129. package/skills-library/_quarantine/README.md +30 -0
  130. package/skills-library/api-patterns/BROADCAST_SCHEDULER_SHARED_EXECUTE_FUNCTION.md +150 -0
  131. package/skills-library/api-patterns/ERROR_RESPONSE_STANDARDS.md +145 -0
  132. package/skills-library/api-patterns/EXPRESS_ROUTE_ORDERING_MIDDLEWARE_INTERCEPTION.md +326 -0
  133. package/skills-library/api-patterns/PAGINATION_PATTERNS.md +137 -0
  134. package/skills-library/api-patterns/PODCAST_PROGRESS_TRACKING_THREE_ROOT_CAUSES.md +277 -0
  135. package/skills-library/api-patterns/RATE_LIMITING_TOGGLE.md +155 -0
  136. package/skills-library/api-patterns/graphql-content-queries.md +708 -0
  137. package/skills-library/appointment-scheduler-design.md +423 -0
  138. package/skills-library/automation/AUTO_POPULATE_COMPLETE_GUIDE.md +631 -0
  139. package/skills-library/automation/CC_WORKFLOW_STUDIO.md +83 -0
  140. package/skills-library/automation/CLAUDE_CODE_SWARM_MODE.md +95 -0
  141. package/skills-library/automation/DAEMON_TRIGGER_FILE_IPC.md +195 -0
  142. package/skills-library/automation/scheduled-content-publishing.md +608 -0
  143. package/skills-library/awesome-workflows/Blogging-Platform-Instructions/view_commands.md +25 -0
  144. package/skills-library/awesome-workflows/CREDENTIAL-SECURITY-WORKFLOW.md +109 -0
  145. package/skills-library/awesome-workflows/DEBUGGING-WORKFLOW.md +124 -0
  146. package/skills-library/awesome-workflows/Design-Review-Workflow/README.md +31 -0
  147. package/skills-library/awesome-workflows/Design-Review-Workflow/design-principles-example.md +129 -0
  148. package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-agent.md +107 -0
  149. package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-claude-md-snippet.md +24 -0
  150. package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-slash-command.md +38 -0
  151. package/skills-library/awesome-workflows/PARALLEL-RESEARCH-WORKFLOW.md +89 -0
  152. package/skills-library/awesome-workflows/PHASE-EXECUTION-WORKFLOW.md +97 -0
  153. package/skills-library/awesome-workflows/SESSION-HANDOFF-WORKFLOW.md +116 -0
  154. package/skills-library/cms-patterns/content-branch-preview.md +515 -0
  155. package/skills-library/cms-patterns/inline-visual-editing.md +666 -0
  156. package/skills-library/cms-patterns/mdx-component-content.md +649 -0
  157. package/skills-library/cms-patterns/media-manager-abstraction.md +827 -0
  158. package/skills-library/cms-patterns/schema-driven-form-generator.md +838 -0
  159. package/skills-library/complexity-metrics/complexity-divider.md +707 -0
  160. package/skills-library/complexity-metrics/work-with-complexity.md +193 -0
  161. package/skills-library/creative-multimedia/animation-stack-guide.md +577 -0
  162. package/skills-library/creative-multimedia/audio-enhancement-pipeline.md +625 -0
  163. package/skills-library/creative-multimedia/content-repurposing-pipeline.md +1146 -0
  164. package/skills-library/creative-multimedia/data-visualization-generator.md +862 -0
  165. package/skills-library/creative-multimedia/doc-to-podcast-pipeline.md +2184 -0
  166. package/skills-library/creative-multimedia/ffmpeg-command-generator.md +405 -0
  167. package/skills-library/creative-multimedia/image-optimization-pipeline.md +605 -0
  168. package/skills-library/creative-multimedia/multi-format-content-generator.md +1759 -0
  169. package/skills-library/creative-multimedia/og-image-generator.md +635 -0
  170. package/skills-library/creative-multimedia/podcast-audio-composition.md +1355 -0
  171. package/skills-library/creative-multimedia/podcast-quality-evaluation.md +1452 -0
  172. package/skills-library/creative-multimedia/podcast-script-generation.md +1841 -0
  173. package/skills-library/creative-multimedia/svg-generation.md +750 -0
  174. package/skills-library/creative-multimedia/text-to-speech-provider-selector.md +1414 -0
  175. package/skills-library/creative-multimedia/transcription-pipeline-selector.md +677 -0
  176. package/skills-library/creative-multimedia/video-streaming-setup.md +559 -0
  177. package/skills-library/database-solutions/AI_RESPONSE_DATABASE_CACHING.md +520 -0
  178. package/skills-library/database-solutions/CONDITIONAL_SQL_MIGRATION_PATTERN.md +119 -0
  179. package/skills-library/database-solutions/DATABASE_COLUMN_NAME_MISMATCH.md +393 -0
  180. package/skills-library/database-solutions/DATABASE_SCHEMA.md +394 -0
  181. package/skills-library/database-solutions/DATABASE_SCHEMA_VERIFICATION_GUIDE.md +348 -0
  182. package/skills-library/database-solutions/DATABASE_STRATEGY.md +71 -0
  183. package/skills-library/database-solutions/ES_MODULE_SEED_SCRIPT_PATTERN.md +52 -0
  184. package/skills-library/database-solutions/MIGRATION_GUIDE.md +3 -0
  185. package/skills-library/database-solutions/PLPGSQL_VARIABLE_CONFLICT_FIX.md +208 -0
  186. package/skills-library/database-solutions/POSTGRESQL_JSONB_DOUBLE_STRINGIFY_FIX.md +245 -0
  187. package/skills-library/database-solutions/POSTGRESQL_LICENSE_TABLE_DESIGN.md +393 -0
  188. package/skills-library/database-solutions/POSTGRESQL_UUID_DOCUMENT_RAG_DUAL_SCOPE.md +732 -0
  189. package/skills-library/database-solutions/POSTGRES_SQL_TEMPLATE_BINDING_ERROR.md +240 -0
  190. package/skills-library/database-solutions/PRISMA_DB_PUSH_DATA_LOSS_PREVENTION.md +141 -0
  191. package/skills-library/database-solutions/PRODUCTION_QUERY_OPTIMIZATION_RESTART_FIX.md +389 -0
  192. package/skills-library/database-solutions/RLS_SECURITY_GUIDE.md +107 -0
  193. package/skills-library/database-solutions/SCHEMA_ENHANCEMENTS_GUIDE.md +373 -0
  194. package/skills-library/database-solutions/SCHEMA_MIGRATION_GUIDE.md +368 -0
  195. package/skills-library/database-solutions/SCHEMA_VERIFICATION_QUICK_REFERENCE.md +104 -0
  196. package/skills-library/database-solutions/ai-erd-generator.md +1213 -0
  197. package/skills-library/database-solutions/content-publishing-states.md +631 -0
  198. package/skills-library/database-solutions/database-schema-designer.md +522 -0
  199. package/skills-library/database-solutions/er-diagram-components.md +569 -0
  200. package/skills-library/database-solutions/er-to-ddl-mapping.md +1405 -0
  201. package/skills-library/database-solutions/erd-creator-textbook-research.md +433 -0
  202. package/skills-library/database-solutions/erd-react-flow-architecture.md +1965 -0
  203. package/skills-library/database-solutions/mariadb-aggregate-function-replacement.md +145 -0
  204. package/skills-library/database-solutions/normalization-validator.md +778 -0
  205. package/skills-library/database-solutions/postgres-full-text-search-content.md +494 -0
  206. package/skills-library/database-solutions/postgresql-to-mysql-runtime-translation.md +286 -0
  207. package/skills-library/database-solutions/regex-alternation-ordering-sql-types.md +92 -0
  208. package/skills-library/database-solutions/reserved-word-context-aware-quoting.md +142 -0
  209. package/skills-library/database-solutions/sql-ddl-generator.md +756 -0
  210. package/skills-library/database-solutions/supabase-connection-pooler-fix.md +102 -0
  211. package/skills-library/deployment-security/CPANEL_NODE_DEPLOYMENT.md +166 -0
  212. package/skills-library/deployment-security/DEPLOYMENT.md +275 -0
  213. package/skills-library/deployment-security/DEPLOYMENT_CHECKLIST.md +363 -0
  214. package/skills-library/deployment-security/DEPLOYMENT_PLAN.md +669 -0
  215. package/skills-library/deployment-security/KNEX_DATABASE_ABSTRACTION.md +444 -0
  216. package/skills-library/deployment-security/LICENSE_KEY_SYSTEM.md +206 -0
  217. package/skills-library/deployment-security/NODE18_DEPENDENCY_COMPATIBILITY.md +284 -0
  218. package/skills-library/deployment-security/PHP_INSTALLER_WIZARD_GUIDE.md +315 -0
  219. package/skills-library/deployment-security/PM2_ENVIRONMENT_VARIABLE_CACHING.md +256 -0
  220. package/skills-library/deployment-security/PM2_MEMORY_EXHAUSTION_FIX.md +370 -0
  221. package/skills-library/deployment-security/PRODUCTION_DEPLOYMENT_GUIDE.md +592 -0
  222. package/skills-library/deployment-security/PRODUCTION_HARDENING_DOCUMENTATION.md +307 -0
  223. package/skills-library/deployment-security/PRODUCTION_RECOVERY_CHERRY_PICK_PATTERN.md +202 -0
  224. package/skills-library/deployment-security/PYINSTALLER_CUDA_WHISPER_BUNDLING.md +236 -0
  225. package/skills-library/deployment-security/SECURITY.md +41 -0
  226. package/skills-library/deployment-security/SMTP_SSL_HOSTNAME_MISMATCH_SHARED_HOSTING.md +220 -0
  227. package/skills-library/deployment-security/SPA_SEO_OPTIMIZATION_CPANEL.md +200 -0
  228. package/skills-library/deployment-security/SUPABASE_EDGE_FUNCTIONS.md +338 -0
  229. package/skills-library/deployment-security/VERCEL_GITHUB_DEPLOYMENT_GUIDE.md +858 -0
  230. package/skills-library/deployment-security/VPS_DEPLOYMENT_READINESS.md +356 -0
  231. package/skills-library/deployment-security/deployment-changes-not-applying.md +241 -0
  232. package/skills-library/deployment-security/env-file-management-production-local.md +203 -0
  233. package/skills-library/deployment-security/express-secure-file-downloads.md +413 -0
  234. package/skills-library/deployment-security/react-production-deployment-desktop-guide.md +2011 -0
  235. package/skills-library/deployment-security/self-hosted-supabase-coolify-guide.md +1684 -0
  236. package/skills-library/deployment-security/unique-features-ai-strategy-plaid-security.md +1613 -0
  237. package/skills-library/deployment-security/vps-deployment.md +135 -0
  238. package/skills-library/document-processing/WORD_EXPORT_MARKDOWN_FORMATTING.md +482 -0
  239. package/skills-library/document-processing/document-ai-landingai-integration.md +677 -0
  240. package/skills-library/document-processing/express-secure-file-downloads-mern.md +413 -0
  241. package/skills-library/document-processing/express-secure-file-downloads.md +413 -0
  242. package/skills-library/document-processing/md-to-word-converter.md +318 -0
  243. package/skills-library/document-processing/pdf-forms-integration/README.md +101 -0
  244. package/skills-library/document-processing/pdf-forms-integration/SKILL.md +662 -0
  245. package/skills-library/ecommerce/ADMIN_PRODUCTS_GUIDE.md +428 -0
  246. package/skills-library/ecommerce/ECOMMERCE_API_REFERENCE.md +776 -0
  247. package/skills-library/ecommerce/ECOMMERCE_COMPLETION_SUMMARY.md +673 -0
  248. package/skills-library/ecommerce/ECOMMERCE_IMPLEMENTATION_GUIDE.md +729 -0
  249. package/skills-library/ecommerce/ECOMMERCE_QUICK_REFERENCE.md +521 -0
  250. package/skills-library/ecommerce/ECOMMERCE_TESTING_CHECKLIST.md +565 -0
  251. package/skills-library/ecommerce/ECOMMERCE_WORKFLOW_GUIDE.md +1059 -0
  252. package/skills-library/ecommerce/PRODUCT_CREATION_EXPANDED.md +522 -0
  253. package/skills-library/ecommerce/agentic-commerce-protocol.md +203 -0
  254. package/skills-library/ecommerce/cart-abandonment-recovery.md +236 -0
  255. package/skills-library/ecommerce/cart-architecture-patterns.md +300 -0
  256. package/skills-library/ecommerce/cart-item-count-indicator.md +264 -0
  257. package/skills-library/ecommerce/checkout-ux-conversion.md +227 -0
  258. package/skills-library/ecommerce/composable-commerce-selection.md +166 -0
  259. package/skills-library/ecommerce/ecommerce-analytics-patterns.md +167 -0
  260. package/skills-library/ecommerce/fraud-detection-patterns.md +179 -0
  261. package/skills-library/ecommerce/inventory-stock-management.md +270 -0
  262. package/skills-library/ecommerce/order-saga-state-machine.md +336 -0
  263. package/skills-library/ecommerce/payment-provider-abstraction.md +245 -0
  264. package/skills-library/ecommerce/pci-compliance-checklist.md +192 -0
  265. package/skills-library/ecommerce/refund-chargeback-handling.md +177 -0
  266. package/skills-library/ecommerce/shipping-carrier-integration.md +218 -0
  267. package/skills-library/ecommerce/webhook-idempotency-patterns.md +253 -0
  268. package/skills-library/excalidraw-diagrams/.github/workflows/ci.yml +558 -0
  269. package/skills-library/excalidraw-diagrams/.github/workflows/prompt-gallery.yml +448 -0
  270. package/skills-library/excalidraw-diagrams/.github/workflows/release.yml +42 -0
  271. package/skills-library/excalidraw-diagrams/.github/workflows/test-reusable-ci.yml +25 -0
  272. package/skills-library/excalidraw-diagrams/CLAUDE.md +57 -0
  273. package/skills-library/excalidraw-diagrams/LICENSE +21 -0
  274. package/skills-library/excalidraw-diagrams/README.md +178 -0
  275. package/skills-library/excalidraw-diagrams/SKILL.md +715 -0
  276. package/skills-library/form-solutions/BUTTON_TYPE_FORM_SUBMISSION.md +336 -0
  277. package/skills-library/form-solutions/FILLABLE_PDF_IMPLEMENTATION.md +226 -0
  278. package/skills-library/form-solutions/SURVEYJS_QUESTIONNAIRE_SYSTEM.md +367 -0
  279. package/skills-library/form-solutions/tiptap-minimal-setup.md +690 -0
  280. package/skills-library/frontend/scholarly-classification-bubble-map.md +149 -0
  281. package/skills-library/infrastructure/ci-cd-pipeline-builder.md +517 -0
  282. package/skills-library/infrastructure/observability-designer.md +264 -0
  283. package/skills-library/infrastructure/performance-profiler.md +621 -0
  284. package/skills-library/installer-wizard-patterns.md +249 -0
  285. package/skills-library/integrations/CLAUDE_CODE_TOKEN_ANALYTICS.md +160 -0
  286. package/skills-library/integrations/CONFIGURABLE_AI_PROVIDER_SELECTION.md +728 -0
  287. package/skills-library/integrations/SOCKET_IO_BROADCAST_ALL_VS_ROOM.md +141 -0
  288. package/skills-library/integrations/VIRTUAL_MEETINGS_IMPLEMENTATION.md +374 -0
  289. package/skills-library/integrations/WORDPRESS_LEARNDASH_DATA_RECOVERY.md +53 -0
  290. package/skills-library/integrations/YOUTUBE_API_SETUP.md +141 -0
  291. package/skills-library/integrations/YOUTUBE_BOOKMARKING_EXPLANATION.md +252 -0
  292. package/skills-library/integrations/YOUTUBE_BOOKMARKING_SOLUTION.md +268 -0
  293. package/skills-library/integrations/YOUTUBE_OAUTH_SETUP_GUIDE.md +200 -0
  294. package/skills-library/integrations/YOUTUBE_VIDEO_FIX_COMPLETE.md +192 -0
  295. package/skills-library/integrations/ai-ml/GEMINI_AI_RAG_PIPELINE_COMPLETE_GUIDE.md +195 -0
  296. package/skills-library/integrations/ai-ml/GEMINI_IMAGE_GENERATION_SETUP.md +64 -0
  297. package/skills-library/integrations/cloudflare/cloudflare-turnstile-debugging.md +202 -0
  298. package/skills-library/integrations/cloudflare/cloudflare-turnstile-implementation.md +476 -0
  299. package/skills-library/integrations/cloudflare-turnstile-debugging.md +202 -0
  300. package/skills-library/integrations/cloudflare-turnstile-implementation.md +476 -0
  301. package/skills-library/integrations/ghost-creator-monetization-pattern.md +454 -0
  302. package/skills-library/integrations/headless-cms-architecture.md +484 -0
  303. package/skills-library/integrations/headless-cms-stack-selection.md +183 -0
  304. package/skills-library/integrations/payload-cms-patterns.md +674 -0
  305. package/skills-library/integrations/realtimestt-openwakeword-cuda-windows.md +229 -0
  306. package/skills-library/integrations/rss-podcast-integration.md +300 -0
  307. package/skills-library/integrations/wordpress/WORDPRESS_LEARNDASH_DATA_RECOVERY.md +53 -0
  308. package/skills-library/integrations/youtube/YOUTUBE_API_SETUP.md +141 -0
  309. package/skills-library/integrations/youtube/YOUTUBE_BOOKMARKING_EXPLANATION.md +252 -0
  310. package/skills-library/integrations/youtube/YOUTUBE_BOOKMARKING_SOLUTION.md +268 -0
  311. package/skills-library/integrations/youtube/YOUTUBE_OAUTH_SETUP_GUIDE.md +200 -0
  312. package/skills-library/integrations/youtube/YOUTUBE_VIDEO_FIX_COMPLETE.md +192 -0
  313. package/skills-library/marketing/campaign-analytics.md +97 -0
  314. package/skills-library/marketing/content-creator.md +105 -0
  315. package/skills-library/marketing/marketing-strategy-pmm.md +94 -0
  316. package/skills-library/marketing/social-media-analyzer.md +81 -0
  317. package/skills-library/methodology/ADVANCED_ORCHESTRATION_PATTERNS.md +401 -0
  318. package/skills-library/methodology/AGENT_SELF_IMPROVEMENT_LOOP.md +179 -0
  319. package/skills-library/methodology/BREATH_BASED_PARALLEL_EXECUTION.md +1 -1
  320. package/skills-library/methodology/CLEANSING_CYCLE.md +358 -0
  321. package/skills-library/methodology/CONFIDENCE_ANNOTATION_PATTERN.md +143 -0
  322. package/skills-library/methodology/CRITICAL_PATTERNS_DOCUMENTATION_COMPLETE.md +204 -0
  323. package/skills-library/methodology/DELIVERABLES_SUMMARY.md +341 -0
  324. package/skills-library/methodology/DIFFICULTY_AWARE_AGENT_ROUTING.md +252 -0
  325. package/skills-library/methodology/EVOLUTIONARY_SKILL_SYNTHESIS.md +219 -0
  326. package/skills-library/methodology/GLOMERULUS_DECISION_GATE.md +223 -0
  327. package/skills-library/methodology/HIBERNATION_SYSTEM.md +231 -0
  328. package/skills-library/methodology/INSTRUMENTATION_OVER_RESTRICTION.md +192 -0
  329. package/skills-library/methodology/MASTER_COMPLETION_SUMMARY.md +444 -0
  330. package/skills-library/methodology/MASTER_SESSION_COMPLETION.md +743 -0
  331. package/skills-library/methodology/MERN_QUICK_REFERENCE.md +358 -0
  332. package/skills-library/methodology/ORGAN_AGENT_MAPPING.md +177 -0
  333. package/skills-library/methodology/PARALLEL_WAVE_BASED_REFACTORING.md +440 -0
  334. package/skills-library/methodology/QUICK_REFERENCE.md +358 -0
  335. package/skills-library/methodology/SDFT_ONPOLICY_SELF_DISTILLATION.md +186 -0
  336. package/skills-library/methodology/SELF_QUESTIONING_TASK_GENERATION.md +270 -0
  337. package/skills-library/methodology/SESSION_COMPLETION_SUMMARY.md +304 -0
  338. package/skills-library/methodology/SESSION_SUMMARY.md +432 -0
  339. package/skills-library/methodology/WARRIOR_WORKFLOW_DEBUGGING_PROTOCOL.md +252 -0
  340. package/skills-library/methodology/tech-debt-tracker.md +570 -0
  341. package/skills-library/parallel-debug/SKILL.md +60 -0
  342. package/skills-library/patterns-standards/API_PATTERN_FIX_SUMMARY.md +236 -0
  343. package/skills-library/patterns-standards/BATCH_OPERATIONS_WITH_PROGRESS_MODAL.md +362 -0
  344. package/skills-library/patterns-standards/CRITICAL_CODING_PATTERNS.md +639 -0
  345. package/skills-library/patterns-standards/DARK_MODE_MODAL_VISIBILITY.md +258 -0
  346. package/skills-library/patterns-standards/ERROR_RESILIENCE_IMPLEMENTATION.md +375 -0
  347. package/skills-library/patterns-standards/ES_MODULE_IMPORT_HOISTING_DOTENV.md +298 -0
  348. package/skills-library/patterns-standards/NESTED_BACKDROP_FILTER_CSS_ARTIFACT_FIX.md +76 -0
  349. package/skills-library/patterns-standards/ORDERED_DETECTOR_PIPELINE_GRACEFUL_FALLBACK.md +333 -0
  350. package/skills-library/patterns-standards/PHASE_IMPORT_ERROR_DEBUGGING.md +271 -0
  351. package/skills-library/patterns-standards/PYNPUT_GLOBAL_HOTKEY_VK_MATCHING.md +252 -0
  352. package/skills-library/patterns-standards/REACT_USEEFFECT_CASCADE_RESET_FIX.md +132 -0
  353. package/skills-library/patterns-standards/SUBMENU_HOVER_DROPDOWN_PATTERN.md +225 -0
  354. package/skills-library/patterns-standards/TAILWIND_TEXT_VISIBILITY_OVERRIDE.md +322 -0
  355. package/skills-library/patterns-standards/THEME_AWARE_CSS_VARIABLES_PATTERN.md +209 -0
  356. package/skills-library/patterns-standards/THEME_USER_OBJECT_PROPERTY_NAMING.md +194 -0
  357. package/skills-library/patterns-standards/TOOLTIP_BLOCKING_CLICKS_FIX.md +267 -0
  358. package/skills-library/patterns-standards/claude-code-plugin-structure.md +235 -0
  359. package/skills-library/patterns-standards/react-i18next-setup.md +429 -0
  360. package/skills-library/patterns-standards/thesys-c1-generative-ui-integration.md +967 -0
  361. package/skills-library/plugin-development/CLAUDE_CODE_COMMAND_REGISTRATION_SILENT_FAILURE.md +315 -0
  362. package/skills-library/plugin-development/plugin-command-namespace-vs-global.md +390 -0
  363. package/skills-library/plugin-development/plugin-doc-auto-generation.md +172 -0
  364. package/skills-library/security/GITHUB_REPO_SECURITY_AUDIT.md +115 -0
  365. package/skills-library/security/admin-deletion-safety.md +396 -0
  366. package/skills-library/security/application-vuln-patterns.md +477 -0
  367. package/skills-library/security/env-secrets-manager.md +686 -0
  368. package/skills-library/security/secure-ai-application-templates.md +347 -0
  369. package/skills-library/security/sql-injection-prevention-postgresjs.md +151 -0
  370. package/skills-library/supabase-connection-pooler-fix.md +102 -0
  371. package/skills-library/system-context/POWERSHELL_BASH_INTEROP.md +82 -0
  372. package/skills-library/system-context/SERVICE_LIFECYCLE_MANAGEMENT.md +119 -0
  373. package/skills-library/system-context/SKILL.md +40 -0
  374. package/skills-library/system-context/WINDOWS_DEV_ENVIRONMENT.md +73 -0
  375. package/skills-library/testing/E2E_PLAYWRIGHT_PATTERNS.md +99 -0
  376. package/skills-library/testing/INTEGRATION_TEST_STRATEGY.md +82 -0
  377. package/skills-library/testing/RED_GREEN_BUGFIX_GATE.md +203 -0
  378. package/skills-library/testing/TEST_DATA_MANAGEMENT.md +69 -0
  379. package/skills-library/testing/VITEST_UNIT_TEST_PATTERNS.md +75 -0
  380. package/skills-library/testing/playwright-api-security-tests.md +202 -0
  381. package/skills-library/toolbox/SKILL.md +84 -0
  382. package/skills-library/toolbox/code-graph-and-web-scraping-mcps.md +237 -0
  383. package/skills-library/ui-ux-pro-max/ACCESSIBILITY_ESSENTIALS.md +115 -0
  384. package/skills-library/ui-ux-pro-max/DESIGN_SYSTEM_SCAFFOLDING.md +133 -0
  385. package/skills-library/ui-ux-pro-max/RESPONSIVE_LAYOUT_PATTERNS.md +119 -0
  386. package/skills-library/ui-ux-pro-max/SKILL.md +386 -0
  387. package/skills-library/ui-ux-pro-max/data/charts.csv +26 -0
  388. package/skills-library/ui-ux-pro-max/data/colors.csv +97 -0
  389. package/skills-library/ui-ux-pro-max/data/icons.csv +101 -0
  390. package/skills-library/ui-ux-pro-max/data/landing.csv +31 -0
  391. package/skills-library/ui-ux-pro-max/data/products.csv +97 -0
  392. package/skills-library/ui-ux-pro-max/data/react-performance.csv +45 -0
  393. package/skills-library/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  394. package/skills-library/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  395. package/skills-library/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  396. package/skills-library/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  397. package/skills-library/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  398. package/skills-library/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  399. package/skills-library/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  400. package/skills-library/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  401. package/skills-library/ui-ux-pro-max/data/stacks/react.csv +54 -0
  402. package/skills-library/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  403. package/skills-library/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  404. package/skills-library/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  405. package/skills-library/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  406. package/skills-library/ui-ux-pro-max/data/styles.csv +68 -0
  407. package/skills-library/ui-ux-pro-max/data/typography.csv +58 -0
  408. package/skills-library/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  409. package/skills-library/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  410. package/skills-library/ui-ux-pro-max/data/web-interface.csv +31 -0
  411. package/skills-library/wordpress-style-theme-components.md +1526 -0
  412. package/templates/ASSUMPTIONS.md +1 -1
  413. package/templates/DECISION_LOG.md +0 -1
  414. package/templates/phase-prompt.md +1 -1
  415. package/templates/phoenix-comparison.md +6 -6
  416. package/templates/skill-api-integration.md +106 -0
  417. package/templates/skill-architecture-pattern.md +92 -0
  418. package/templates/skill-debug-pattern.md +98 -0
  419. package/templates/skill-devops-recipe.md +107 -0
  420. package/templates/skill-general.md +65 -0
  421. package/templates/skill-ui-component.md +113 -0
  422. package/tools/uat-runner.py +179 -0
  423. package/version.json +7 -3
  424. package/workflows/handoff-session.md +2 -2
  425. package/workflows/new-project.md +2 -2
  426. package/workflows/plan-phase.md +1 -1
  427. package/.claude-plugin/plugin.json +0 -64
  428. package/skills-library/_general/methodology/LIVE_BREADCRUMB_PROTOCOL.md +0 -242
  429. package/skills-library/_general/methodology/llm-judge-memory-crud.md +0 -241
  430. package/skills-library/methodology/REFLEXION_MEMORY_PATTERN.md +0 -183
  431. package/skills-library/methodology/RESEARCH_BACKED_WORKFLOW_UPGRADE.md +0 -263
  432. package/skills-library/methodology/SABBATH_REST_PATTERN.md +0 -267
  433. package/skills-library/methodology/STONE_AND_SCAFFOLD.md +0 -220
  434. package/skills-library/specialists/api-architecture/api-designer.md +0 -49
  435. package/skills-library/specialists/api-architecture/graphql-architect.md +0 -49
  436. package/skills-library/specialists/api-architecture/mcp-developer.md +0 -51
  437. package/skills-library/specialists/api-architecture/microservices-architect.md +0 -50
  438. package/skills-library/specialists/api-architecture/websocket-engineer.md +0 -48
  439. package/skills-library/specialists/backend/django-expert.md +0 -52
  440. package/skills-library/specialists/backend/fastapi-expert.md +0 -52
  441. package/skills-library/specialists/backend/laravel-specialist.md +0 -52
  442. package/skills-library/specialists/backend/nestjs-expert.md +0 -51
  443. package/skills-library/specialists/backend/rails-expert.md +0 -53
  444. package/skills-library/specialists/backend/spring-boot-engineer.md +0 -56
  445. package/skills-library/specialists/data-ml/fine-tuning-expert.md +0 -48
  446. package/skills-library/specialists/data-ml/ml-pipeline.md +0 -47
  447. package/skills-library/specialists/data-ml/pandas-pro.md +0 -47
  448. package/skills-library/specialists/data-ml/rag-architect.md +0 -51
  449. package/skills-library/specialists/data-ml/spark-engineer.md +0 -47
  450. package/skills-library/specialists/frontend/angular-architect.md +0 -52
  451. package/skills-library/specialists/frontend/flutter-expert.md +0 -51
  452. package/skills-library/specialists/frontend/nextjs-developer.md +0 -54
  453. package/skills-library/specialists/frontend/react-native-expert.md +0 -50
  454. package/skills-library/specialists/frontend/vue-expert.md +0 -51
  455. package/skills-library/specialists/infrastructure/chaos-engineer.md +0 -74
  456. package/skills-library/specialists/infrastructure/cloud-architect.md +0 -70
  457. package/skills-library/specialists/infrastructure/database-optimizer.md +0 -64
  458. package/skills-library/specialists/infrastructure/devops-engineer.md +0 -70
  459. package/skills-library/specialists/infrastructure/kubernetes-specialist.md +0 -52
  460. package/skills-library/specialists/infrastructure/monitoring-expert.md +0 -70
  461. package/skills-library/specialists/infrastructure/sre-engineer.md +0 -70
  462. package/skills-library/specialists/infrastructure/terraform-engineer.md +0 -51
  463. package/skills-library/specialists/languages/cpp-pro.md +0 -74
  464. package/skills-library/specialists/languages/csharp-developer.md +0 -69
  465. package/skills-library/specialists/languages/dotnet-core-expert.md +0 -54
  466. package/skills-library/specialists/languages/golang-pro.md +0 -51
  467. package/skills-library/specialists/languages/java-architect.md +0 -49
  468. package/skills-library/specialists/languages/javascript-pro.md +0 -68
  469. package/skills-library/specialists/languages/kotlin-specialist.md +0 -68
  470. package/skills-library/specialists/languages/php-pro.md +0 -49
  471. package/skills-library/specialists/languages/python-pro.md +0 -52
  472. package/skills-library/specialists/languages/react-expert.md +0 -51
  473. package/skills-library/specialists/languages/rust-engineer.md +0 -50
  474. package/skills-library/specialists/languages/sql-pro.md +0 -56
  475. package/skills-library/specialists/languages/swift-expert.md +0 -69
  476. package/skills-library/specialists/languages/typescript-pro.md +0 -51
  477. package/skills-library/specialists/platform/atlassian-mcp.md +0 -52
  478. package/skills-library/specialists/platform/embedded-systems.md +0 -53
  479. package/skills-library/specialists/platform/game-developer.md +0 -53
  480. package/skills-library/specialists/platform/salesforce-developer.md +0 -53
  481. package/skills-library/specialists/platform/shopify-expert.md +0 -49
  482. package/skills-library/specialists/platform/wordpress-pro.md +0 -49
  483. package/skills-library/specialists/quality/code-documenter.md +0 -51
  484. package/skills-library/specialists/quality/code-reviewer.md +0 -67
  485. package/skills-library/specialists/quality/debugging-wizard.md +0 -51
  486. package/skills-library/specialists/quality/fullstack-guardian.md +0 -51
  487. package/skills-library/specialists/quality/legacy-modernizer.md +0 -50
  488. package/skills-library/specialists/quality/playwright-expert.md +0 -65
  489. package/skills-library/specialists/quality/spec-miner.md +0 -56
  490. package/skills-library/specialists/quality/test-master.md +0 -65
  491. package/skills-library/specialists/security/secure-code-guardian.md +0 -55
  492. package/skills-library/specialists/security/security-reviewer.md +0 -53
  493. package/skills-library/specialists/workflow/architecture-designer.md +0 -53
  494. package/skills-library/specialists/workflow/cli-developer.md +0 -70
  495. package/skills-library/specialists/workflow/feature-forge.md +0 -65
  496. package/skills-library/specialists/workflow/prompt-engineer.md +0 -54
  497. package/skills-library/specialists/workflow/the-fool.md +0 -62
  498. /package/skills-library/{performance → _general/performance}/cache-augmented-generation.md +0 -0
  499. /package/skills-library/{debugging → parallel-debug}/FAILURE_TAXONOMY_CLASSIFICATION.md +0 -0
  500. /package/skills-library/{debugging → parallel-debug}/THREE_AGENT_HYPOTHESIS_DEBUGGING.md +0 -0
@@ -0,0 +1,1841 @@
1
+ ---
2
+ name: podcast-script-generation
3
+ category: creative-multimedia
4
+ version: 1.0.0
5
+ contributed: 2026-03-10
6
+ contributor: dominion-flow-research
7
+ last_updated: 2026-03-10
8
+ tags: [podcast, script, dialogue, multi-agent, content-generation, rag, document-analysis]
9
+ difficulty: hard
10
+ ---
11
+ ## Description
12
+
13
+ AI-powered podcast script generation from documents using a multi-agent pattern. Transforms PDFs, articles, YouTube transcripts, and raw text into structured, natural-sounding podcast scripts with multiple speaker formats: two-speaker deep-dive, panel discussion, solo narration, and debate. Uses the PodAgent three-agent architecture (Host, Guest, Writer) with faithfulness verification to prevent hallucination in long-form output.
14
+
15
+ ## When to Use
16
+
17
+ - Converting research papers, reports, or articles into podcast-format audio content
18
+ - Building a "NotebookLM-style" document-to-podcast feature in your app
19
+ - Generating interview scripts from source material for TTS pipelines
20
+ - Creating educational audio content from textbooks or lesson plans
21
+ - Repurposing blog posts, sermons, or documentation into conversational audio
22
+ - Generating script drafts for human hosts to review and record
23
+
24
+ ---
25
+
26
+ ## The PodAgent Multi-Agent Pattern
27
+
28
+ Based on PodAgent (ACL 2025, arXiv 2503.00455) -- 87.4% voice-role matching accuracy.
29
+
30
+ The key insight: direct single-prompt generation produces flat, monotonous scripts. Splitting the task across three specialized agents produces natural dialogue with distinct voices, better pacing, and verifiable faithfulness to source material.
31
+
32
+ ### Architecture
33
+
34
+ ```
35
+ Source Documents
36
+ |
37
+ v
38
+ +-------------------+
39
+ | Host Agent | Formulates questions, creates guest profiles,
40
+ | (Interviewer) | drives conversation flow, sets topic transitions
41
+ +-------------------+
42
+ |
43
+ | questions + guest profile
44
+ v
45
+ +-------------------+
46
+ | Guest Agent(s) | Provides domain expertise from source documents,
47
+ | (Expert) | answers Host's questions with citations
48
+ +-------------------+
49
+ |
50
+ | raw Host-Guest dialogue
51
+ v
52
+ +-------------------+
53
+ | Writer Agent | Composes final script from dialogue, adds
54
+ | (Producer) | transitions, pacing cues, tone directions
55
+ +-------------------+
56
+ |
57
+ v
58
+ +-------------------+
59
+ | Faithfulness | Verifies every claim against source text,
60
+ | Checker | flags hallucinations, suggests corrections
61
+ +-------------------+
62
+ |
63
+ v
64
+ Structured PodcastScript (JSON)
65
+ ```
66
+
67
+ ### TypeScript Types
68
+
69
+ ```typescript
70
+ // ─── Core Types ─────────────────────────────────────────────────────────────
71
+
72
+ interface PodcastScript {
73
+ title: string;
74
+ duration: '5min' | '15min' | '30min' | '60min';
75
+ speakers: Speaker[];
76
+ segments: ScriptSegment[];
77
+ metadata: PodcastMetadata;
78
+ }
79
+
80
+ interface Speaker {
81
+ id: string;
82
+ name: string;
83
+ role: 'host' | 'guest' | 'narrator';
84
+ voiceProfile: VoiceProfile;
85
+ expertise?: string; // For guests: their domain knowledge area
86
+ }
87
+
88
+ interface VoiceProfile {
89
+ tone: 'warm' | 'authoritative' | 'curious' | 'measured' | 'energetic';
90
+ pace: 'slow' | 'moderate' | 'fast';
91
+ style: 'conversational' | 'formal' | 'storytelling' | 'academic';
92
+ ttsVoiceId?: string; // Provider-specific voice ID for TTS
93
+ }
94
+
95
+ interface ScriptSegment {
96
+ speaker: string; // Speaker ID reference
97
+ text: string; // The spoken words
98
+ direction: string; // e.g., "(enthusiastically)", "(thoughtfully)"
99
+ timing?: number; // Estimated seconds for this segment
100
+ segmentType: SegmentType;
101
+ sourceReference?: string; // Citation back to source document chunk
102
+ }
103
+
104
+ type SegmentType =
105
+ | 'intro'
106
+ | 'question'
107
+ | 'answer'
108
+ | 'transition'
109
+ | 'deep-dive'
110
+ | 'anecdote'
111
+ | 'summary'
112
+ | 'outro'
113
+ | 'ad-break';
114
+
115
+ interface PodcastMetadata {
116
+ sourceDocuments: string[]; // File paths or URLs of source material
117
+ generatedAt: string; // ISO timestamp
118
+ wordCount: number;
119
+ estimatedDuration: number; // Seconds
120
+ format: PodcastFormat;
121
+ faithfulnessScore: number; // 0-1, from verification step
122
+ keyTopics: string[];
123
+ }
124
+
125
+ type PodcastFormat = 'two-speaker' | 'panel' | 'solo-narration' | 'debate';
126
+
127
+ // ─── Pipeline Types ─────────────────────────────────────────────────────────
128
+
129
+ interface DocumentChunk {
130
+ id: string;
131
+ text: string;
132
+ source: string; // File name or URL
133
+ pageNumber?: number;
134
+ sectionTitle?: string;
135
+ embedding?: number[]; // For semantic search during generation
136
+ }
137
+
138
+ interface KeyPoint {
139
+ point: string;
140
+ importance: 'critical' | 'important' | 'supplementary';
141
+ sourceChunkIds: string[]; // Which chunks support this point
142
+ suggestedQuestions: string[]; // Questions the Host could ask about this
143
+ }
144
+
145
+ interface PodcastOutline {
146
+ title: string;
147
+ hook: string; // Opening hook to grab listener attention
148
+ segments: OutlineSegment[];
149
+ closingThought: string;
150
+ }
151
+
152
+ interface OutlineSegment {
153
+ topic: string;
154
+ keyPoints: string[];
155
+ estimatedDuration: number; // Seconds
156
+ transitionFrom?: string; // How to flow from previous segment
157
+ }
158
+
159
+ interface FaithfulnessReport {
160
+ overallScore: number; // 0-1
161
+ segmentScores: Array<{
162
+ segmentIndex: number;
163
+ score: number;
164
+ claims: Array<{
165
+ claim: string;
166
+ supported: boolean;
167
+ sourceEvidence?: string;
168
+ correction?: string;
169
+ }>;
170
+ }>;
171
+ flaggedSegments: number[]; // Indices of segments scoring below 0.7
172
+ }
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Document-to-Script Pipeline
178
+
179
+ ### Complete Pipeline (6 Steps)
180
+
181
+ ```
182
+ Step 1: Document Ingestion
183
+ - Parse PDF/DOCX/URL/YouTube transcript
184
+ - Extract raw text, clean formatting artifacts
185
+ - Preserve section structure for context
186
+
187
+ Step 2: Semantic Chunking
188
+ - Split by semantic boundaries (not fixed-size)
189
+ - 300-500 token chunks with 50-token overlap
190
+ - Preserve paragraph/section context in metadata
191
+
192
+ Step 3: Key Point Extraction
193
+ - AI identifies top N discussion-worthy points
194
+ - Rank by importance and listener interest
195
+ - Generate potential questions per point
196
+
197
+ Step 4: Outline Generation
198
+ - Structure: hook --> intro --> segments --> summary --> outro
199
+ - Assign duration budgets per segment
200
+ - Plan transitions between topics
201
+
202
+ Step 5: Multi-Agent Script Generation
203
+ - Host Agent generates questions and flow
204
+ - Guest Agent provides expert responses from source
205
+ - Writer Agent polishes into final script
206
+ - Generate PER-CHUNK, not all at once (see Hallucination Fix)
207
+
208
+ Step 6: Faithfulness Verification
209
+ - Check every claim against source documents
210
+ - Score each segment independently
211
+ - Flag and correct hallucinations before output
212
+ ```
213
+
214
+ ### Step 1: Document Ingestion
215
+
216
+ ```typescript
217
+ import { promises as fs } from 'fs';
218
+ import path from 'path';
219
+
220
+ // ─── Document Parser ────────────────────────────────────────────────────────
221
+
222
+ interface ParsedDocument {
223
+ title: string;
224
+ text: string;
225
+ sections: Array<{ heading: string; content: string }>;
226
+ metadata: { source: string; pageCount?: number; wordCount: number };
227
+ }
228
+
229
+ async function parseDocument(filePath: string): Promise<ParsedDocument> {
230
+ const ext = path.extname(filePath).toLowerCase();
231
+
232
+ switch (ext) {
233
+ case '.pdf':
234
+ return parsePDF(filePath);
235
+ case '.txt':
236
+ case '.md':
237
+ return parseText(filePath);
238
+ case '.html':
239
+ return parseHTML(filePath);
240
+ default:
241
+ throw new Error(`Unsupported file type: ${ext}`);
242
+ }
243
+ }
244
+
245
+ async function parseText(filePath: string): Promise<ParsedDocument> {
246
+ const raw = await fs.readFile(filePath, 'utf-8');
247
+ const lines = raw.split('\n');
248
+ const title = lines[0]?.replace(/^#+\s*/, '') || path.basename(filePath);
249
+
250
+ // Extract sections by markdown headers or blank-line separation
251
+ const sections: Array<{ heading: string; content: string }> = [];
252
+ let currentHeading = 'Introduction';
253
+ let currentContent: string[] = [];
254
+
255
+ for (const line of lines) {
256
+ if (line.match(/^#{1,3}\s+/)) {
257
+ if (currentContent.length > 0) {
258
+ sections.push({ heading: currentHeading, content: currentContent.join('\n').trim() });
259
+ }
260
+ currentHeading = line.replace(/^#+\s*/, '');
261
+ currentContent = [];
262
+ } else {
263
+ currentContent.push(line);
264
+ }
265
+ }
266
+ if (currentContent.length > 0) {
267
+ sections.push({ heading: currentHeading, content: currentContent.join('\n').trim() });
268
+ }
269
+
270
+ return {
271
+ title,
272
+ text: raw,
273
+ sections,
274
+ metadata: {
275
+ source: filePath,
276
+ wordCount: raw.split(/\s+/).length,
277
+ },
278
+ };
279
+ }
280
+
281
+ async function parsePDF(filePath: string): Promise<ParsedDocument> {
282
+ // Use pdf-parse (npm install pdf-parse)
283
+ const pdfParse = (await import('pdf-parse')).default;
284
+ const buffer = await fs.readFile(filePath);
285
+ const data = await pdfParse(buffer);
286
+
287
+ return {
288
+ title: data.info?.Title || path.basename(filePath, '.pdf'),
289
+ text: data.text,
290
+ sections: [{ heading: 'Full Document', content: data.text }],
291
+ metadata: {
292
+ source: filePath,
293
+ pageCount: data.numpages,
294
+ wordCount: data.text.split(/\s+/).length,
295
+ },
296
+ };
297
+ }
298
+
299
+ async function parseHTML(filePath: string): Promise<ParsedDocument> {
300
+ // Use cheerio for HTML parsing (npm install cheerio)
301
+ const cheerio = await import('cheerio');
302
+ const html = await fs.readFile(filePath, 'utf-8');
303
+ const $ = cheerio.load(html);
304
+
305
+ // Remove scripts, styles, nav, footer
306
+ $('script, style, nav, footer, header, aside').remove();
307
+
308
+ const title = $('h1').first().text() || $('title').text() || path.basename(filePath);
309
+ const text = $('body').text().replace(/\s+/g, ' ').trim();
310
+
311
+ return {
312
+ title,
313
+ text,
314
+ sections: [{ heading: 'Content', content: text }],
315
+ metadata: {
316
+ source: filePath,
317
+ wordCount: text.split(/\s+/).length,
318
+ },
319
+ };
320
+ }
321
+ ```
322
+
323
+ ### Step 2: Semantic Chunking
324
+
325
+ ```typescript
326
+ // ─── Semantic Chunking ──────────────────────────────────────────────────────
327
+ // Critical: Use semantic boundaries, NOT fixed-size windows.
328
+ // Fixed-size chunking splits mid-sentence and loses context.
329
+
330
+ interface ChunkConfig {
331
+ targetTokens: number; // Target chunk size (300-500 tokens)
332
+ overlapTokens: number; // Overlap between chunks (50 tokens)
333
+ preserveParagraphs: boolean;
334
+ }
335
+
336
+ function semanticChunk(
337
+ document: ParsedDocument,
338
+ config: ChunkConfig = { targetTokens: 400, overlapTokens: 50, preserveParagraphs: true }
339
+ ): DocumentChunk[] {
340
+ const chunks: DocumentChunk[] = [];
341
+ let chunkIndex = 0;
342
+
343
+ for (const section of document.sections) {
344
+ // Split by paragraph boundaries first
345
+ const paragraphs = section.content
346
+ .split(/\n\n+/)
347
+ .map(p => p.trim())
348
+ .filter(p => p.length > 0);
349
+
350
+ let currentChunk: string[] = [];
351
+ let currentTokenCount = 0;
352
+
353
+ for (const paragraph of paragraphs) {
354
+ const paragraphTokens = estimateTokens(paragraph);
355
+
356
+ // If adding this paragraph exceeds target, finalize current chunk
357
+ if (currentTokenCount + paragraphTokens > config.targetTokens && currentChunk.length > 0) {
358
+ const chunkText = currentChunk.join('\n\n');
359
+ chunks.push({
360
+ id: `chunk-${chunkIndex++}`,
361
+ text: chunkText,
362
+ source: document.metadata.source,
363
+ sectionTitle: section.heading,
364
+ });
365
+
366
+ // Keep overlap: last paragraph carries into next chunk
367
+ if (config.overlapTokens > 0) {
368
+ const lastParagraph = currentChunk[currentChunk.length - 1];
369
+ currentChunk = [lastParagraph];
370
+ currentTokenCount = estimateTokens(lastParagraph);
371
+ } else {
372
+ currentChunk = [];
373
+ currentTokenCount = 0;
374
+ }
375
+ }
376
+
377
+ currentChunk.push(paragraph);
378
+ currentTokenCount += paragraphTokens;
379
+ }
380
+
381
+ // Finalize remaining content in section
382
+ if (currentChunk.length > 0) {
383
+ chunks.push({
384
+ id: `chunk-${chunkIndex++}`,
385
+ text: currentChunk.join('\n\n'),
386
+ source: document.metadata.source,
387
+ sectionTitle: section.heading,
388
+ });
389
+ }
390
+ }
391
+
392
+ return chunks;
393
+ }
394
+
395
+ function estimateTokens(text: string): number {
396
+ // Rough estimate: 1 token per ~4 characters for English text
397
+ return Math.ceil(text.length / 4);
398
+ }
399
+ ```
400
+
401
+ ### Step 3: Key Point Extraction
402
+
403
+ ```typescript
404
+ import Anthropic from '@anthropic-ai/sdk';
405
+
406
+ // ─── Key Point Extraction ───────────────────────────────────────────────────
407
+
408
+ async function extractKeyPoints(
409
+ chunks: DocumentChunk[],
410
+ targetPoints: number,
411
+ client: Anthropic
412
+ ): Promise<KeyPoint[]> {
413
+ // Process chunks in batches to stay within context limits
414
+ const batchSize = 10;
415
+ const allPoints: KeyPoint[] = [];
416
+
417
+ for (let i = 0; i < chunks.length; i += batchSize) {
418
+ const batch = chunks.slice(i, i + batchSize);
419
+ const batchText = batch.map(c =>
420
+ `[${c.id}] (Section: ${c.sectionTitle || 'N/A'})\n${c.text}`
421
+ ).join('\n\n---\n\n');
422
+
423
+ const response = await client.messages.create({
424
+ model: 'claude-sonnet-4-20250514',
425
+ max_tokens: 4096,
426
+ messages: [{
427
+ role: 'user',
428
+ content: `Analyze these document chunks and extract the most discussion-worthy points for a podcast conversation.
429
+
430
+ DOCUMENT CHUNKS:
431
+ ${batchText}
432
+
433
+ For each point, provide:
434
+ 1. A clear statement of the point
435
+ 2. Its importance level (critical / important / supplementary)
436
+ 3. Which chunk IDs support it
437
+ 4. 2-3 questions a podcast host could ask about this point
438
+
439
+ Return JSON array:
440
+ [
441
+ {
442
+ "point": "statement of the key point",
443
+ "importance": "critical|important|supplementary",
444
+ "sourceChunkIds": ["chunk-0", "chunk-1"],
445
+ "suggestedQuestions": ["Question 1?", "Question 2?"]
446
+ }
447
+ ]
448
+
449
+ Extract ${Math.ceil(targetPoints / Math.ceil(chunks.length / batchSize))} points from this batch.
450
+ Return ONLY valid JSON.`,
451
+ }],
452
+ });
453
+
454
+ const text = response.content[0].type === 'text' ? response.content[0].text : '[]';
455
+ const parsed = JSON.parse(text.replace(/^```json\n?/, '').replace(/\n?```$/, ''));
456
+ allPoints.push(...parsed);
457
+ }
458
+
459
+ // Rank and deduplicate
460
+ const ranked = allPoints
461
+ .sort((a, b) => {
462
+ const importanceOrder = { critical: 0, important: 1, supplementary: 2 };
463
+ return importanceOrder[a.importance] - importanceOrder[b.importance];
464
+ })
465
+ .slice(0, targetPoints);
466
+
467
+ return ranked;
468
+ }
469
+ ```
470
+
471
+ ### Step 4: Outline Generation
472
+
473
+ ```typescript
474
+ // ─── Outline Generation ─────────────────────────────────────────────────────
475
+
476
+ async function generateOutline(
477
+ keyPoints: KeyPoint[],
478
+ duration: '5min' | '15min' | '30min' | '60min',
479
+ format: PodcastFormat,
480
+ client: Anthropic
481
+ ): Promise<PodcastOutline> {
482
+ const durationMap = {
483
+ '5min': { seconds: 300, points: 3, segmentCount: 3 },
484
+ '15min': { seconds: 900, points: 7, segmentCount: 5 },
485
+ '30min': { seconds: 1800, points: 12, segmentCount: 8 },
486
+ '60min': { seconds: 3600, points: 20, segmentCount: 12 },
487
+ };
488
+
489
+ const config = durationMap[duration];
490
+ const selectedPoints = keyPoints.slice(0, config.points);
491
+
492
+ const response = await client.messages.create({
493
+ model: 'claude-sonnet-4-20250514',
494
+ max_tokens: 4096,
495
+ messages: [{
496
+ role: 'user',
497
+ content: `Create a podcast outline for a ${duration} ${format} episode.
498
+
499
+ KEY POINTS TO COVER:
500
+ ${selectedPoints.map((p, i) => `${i + 1}. [${p.importance}] ${p.point}`).join('\n')}
501
+
502
+ FORMAT: ${format}
503
+ TARGET DURATION: ${config.seconds} seconds
504
+ TARGET SEGMENTS: ${config.segmentCount}
505
+
506
+ Create an outline with:
507
+ - A compelling hook (first 15-30 seconds to grab attention)
508
+ - Logical flow between topics with smooth transitions
509
+ - Duration budget per segment (must sum to ~${config.seconds} seconds)
510
+ - A memorable closing thought
511
+
512
+ Return JSON:
513
+ {
514
+ "title": "Episode title",
515
+ "hook": "Opening hook text",
516
+ "segments": [
517
+ {
518
+ "topic": "Segment topic",
519
+ "keyPoints": ["point 1", "point 2"],
520
+ "estimatedDuration": 120,
521
+ "transitionFrom": "How to transition from previous segment"
522
+ }
523
+ ],
524
+ "closingThought": "Memorable closing"
525
+ }
526
+
527
+ Return ONLY valid JSON.`,
528
+ }],
529
+ });
530
+
531
+ const text = response.content[0].type === 'text' ? response.content[0].text : '{}';
532
+ return JSON.parse(text.replace(/^```json\n?/, '').replace(/\n?```$/, ''));
533
+ }
534
+ ```
535
+
536
+ ### Step 5: Multi-Agent Script Generation
537
+
538
+ ```typescript
539
+ // ─── Multi-Agent Script Generation ──────────────────────────────────────────
540
+ // CRITICAL: Generate per-segment, not all at once.
541
+ // See "The Hallucination Chunking Fix" section below.
542
+
543
+ async function generateScript(
544
+ outline: PodcastOutline,
545
+ chunks: DocumentChunk[],
546
+ keyPoints: KeyPoint[],
547
+ format: PodcastFormat,
548
+ speakers: Speaker[],
549
+ client: Anthropic
550
+ ): Promise<ScriptSegment[]> {
551
+ const allSegments: ScriptSegment[] = [];
552
+
553
+ // Generate intro
554
+ const introSegments = await generateIntroSegments(
555
+ outline, speakers, format, client
556
+ );
557
+ allSegments.push(...introSegments);
558
+
559
+ // Generate each content segment independently (hallucination fix)
560
+ for (let i = 0; i < outline.segments.length; i++) {
561
+ const outlineSeg = outline.segments[i];
562
+
563
+ // Find relevant source chunks for this segment
564
+ const relevantChunks = findRelevantChunks(outlineSeg.keyPoints, chunks, keyPoints);
565
+
566
+ const segmentScript = await generateSegmentDialogue(
567
+ outlineSeg,
568
+ relevantChunks,
569
+ speakers,
570
+ format,
571
+ i === 0, // isFirstSegment
572
+ outline.segments[i - 1], // previousSegment (for transition)
573
+ client
574
+ );
575
+
576
+ allSegments.push(...segmentScript);
577
+ }
578
+
579
+ // Generate outro
580
+ const outroSegments = await generateOutroSegments(
581
+ outline, speakers, format, client
582
+ );
583
+ allSegments.push(...outroSegments);
584
+
585
+ return allSegments;
586
+ }
587
+
588
+ async function generateSegmentDialogue(
589
+ segment: OutlineSegment,
590
+ relevantChunks: DocumentChunk[],
591
+ speakers: Speaker[],
592
+ format: PodcastFormat,
593
+ isFirstSegment: boolean,
594
+ previousSegment: OutlineSegment | undefined,
595
+ client: Anthropic
596
+ ): Promise<ScriptSegment[]> {
597
+ const host = speakers.find(s => s.role === 'host')!;
598
+ const guests = speakers.filter(s => s.role === 'guest');
599
+
600
+ // ── Step A: Host Agent generates questions ──
601
+ const hostResponse = await client.messages.create({
602
+ model: 'claude-sonnet-4-20250514',
603
+ max_tokens: 2048,
604
+ system: buildHostAgentSystem(host, format),
605
+ messages: [{
606
+ role: 'user',
607
+ content: `Generate the HOST's contributions for this podcast segment.
608
+
609
+ SEGMENT TOPIC: ${segment.topic}
610
+ KEY POINTS TO COVER: ${segment.keyPoints.join('; ')}
611
+ ${previousSegment ? `TRANSITION FROM: ${previousSegment.topic}` : 'THIS IS THE FIRST CONTENT SEGMENT'}
612
+ TARGET DURATION: ${segment.estimatedDuration} seconds (~${Math.round(segment.estimatedDuration / 60 * 150)} words)
613
+
614
+ Return JSON array of host contributions:
615
+ [
616
+ {
617
+ "type": "transition|question|follow-up|reaction|summary",
618
+ "text": "What the host says",
619
+ "direction": "(tone/delivery direction)",
620
+ "targetGuest": "guest-id or null"
621
+ }
622
+ ]
623
+
624
+ Generate 3-5 contributions that drive the conversation naturally.
625
+ Return ONLY valid JSON.`,
626
+ }],
627
+ });
628
+
629
+ const hostContributions = JSON.parse(
630
+ (hostResponse.content[0] as { type: string; text: string }).text
631
+ .replace(/^```json\n?/, '').replace(/\n?```$/, '')
632
+ );
633
+
634
+ // ── Step B: Guest Agent generates responses ──
635
+ const sourceContext = relevantChunks.map(c => c.text).join('\n\n---\n\n');
636
+
637
+ const guestResponses: Array<{ guestId: string; responses: any[] }> = [];
638
+
639
+ for (const guest of guests) {
640
+ const guestResponse = await client.messages.create({
641
+ model: 'claude-sonnet-4-20250514',
642
+ max_tokens: 3072,
643
+ system: buildGuestAgentSystem(guest, format),
644
+ messages: [{
645
+ role: 'user',
646
+ content: `You are responding to the host's questions as a guest expert.
647
+
648
+ SOURCE MATERIAL (base ALL responses on this):
649
+ ${sourceContext}
650
+
651
+ HOST'S QUESTIONS/PROMPTS:
652
+ ${hostContributions.map((h: any, i: number) => `${i + 1}. [${h.type}] ${h.text}`).join('\n')}
653
+
654
+ SEGMENT TOPIC: ${segment.topic}
655
+
656
+ For each host contribution that is directed at you or is a general question, provide a response.
657
+ CRITICAL: Every factual claim MUST be supported by the source material above. If the source does not cover something, say "that's beyond what we're looking at today" rather than making something up.
658
+
659
+ Return JSON array:
660
+ [
661
+ {
662
+ "respondsTo": 1,
663
+ "text": "Guest's response",
664
+ "direction": "(tone/delivery direction)",
665
+ "sourceEvidence": "Brief quote or reference from source material that supports this"
666
+ }
667
+ ]
668
+
669
+ Return ONLY valid JSON.`,
670
+ }],
671
+ });
672
+
673
+ const parsed = JSON.parse(
674
+ (guestResponse.content[0] as { type: string; text: string }).text
675
+ .replace(/^```json\n?/, '').replace(/\n?```$/, '')
676
+ );
677
+ guestResponses.push({ guestId: guest.id, responses: parsed });
678
+ }
679
+
680
+ // ── Step C: Writer Agent composes final dialogue ──
681
+ const writerResponse = await client.messages.create({
682
+ model: 'claude-sonnet-4-20250514',
683
+ max_tokens: 4096,
684
+ system: buildWriterAgentSystem(format),
685
+ messages: [{
686
+ role: 'user',
687
+ content: `Compose the final podcast script segment from these raw dialogue elements.
688
+
689
+ HOST CONTRIBUTIONS:
690
+ ${JSON.stringify(hostContributions, null, 2)}
691
+
692
+ GUEST RESPONSES:
693
+ ${JSON.stringify(guestResponses, null, 2)}
694
+
695
+ SPEAKERS:
696
+ ${speakers.map(s => `${s.id}: ${s.name} (${s.role}, ${s.voiceProfile.tone} tone)`).join('\n')}
697
+
698
+ RULES:
699
+ - Interleave host and guest naturally -- no long monologues
700
+ - Add brief reactions ("Exactly.", "That's fascinating.", "Right, and...")
701
+ - Include delivery directions in parentheses
702
+ - Keep each speaking turn to 2-4 sentences max
703
+ - Add natural pauses and thinking moments
704
+ - The segment should flow as real conversation, not a Q&A interview
705
+ ${isFirstSegment ? '- Include the transition into this first topic' : `- Start with transition: ${segment.transitionFrom}`}
706
+
707
+ Return JSON array of ScriptSegment objects:
708
+ [
709
+ {
710
+ "speaker": "speaker-id",
711
+ "text": "What they say",
712
+ "direction": "(delivery direction)",
713
+ "timing": estimated_seconds,
714
+ "segmentType": "question|answer|transition|deep-dive|anecdote|summary",
715
+ "sourceReference": "chunk-id or null"
716
+ }
717
+ ]
718
+
719
+ Return ONLY valid JSON.`,
720
+ }],
721
+ });
722
+
723
+ const text = (writerResponse.content[0] as { type: string; text: string }).text;
724
+ return JSON.parse(text.replace(/^```json\n?/, '').replace(/\n?```$/, ''));
725
+ }
726
+
727
+ // ─── Helper: Find Relevant Chunks ──────────────────────────────────────────
728
+
729
+ function findRelevantChunks(
730
+ segmentKeyPoints: string[],
731
+ allChunks: DocumentChunk[],
732
+ allKeyPoints: KeyPoint[]
733
+ ): DocumentChunk[] {
734
+ // Find which KeyPoint objects match this segment's points
735
+ const matchingPoints = allKeyPoints.filter(kp =>
736
+ segmentKeyPoints.some(sp =>
737
+ sp.toLowerCase().includes(kp.point.toLowerCase().slice(0, 40)) ||
738
+ kp.point.toLowerCase().includes(sp.toLowerCase().slice(0, 40))
739
+ )
740
+ );
741
+
742
+ // Collect all referenced chunk IDs
743
+ const chunkIds = new Set<string>();
744
+ for (const point of matchingPoints) {
745
+ for (const id of point.sourceChunkIds) {
746
+ chunkIds.add(id);
747
+ }
748
+ }
749
+
750
+ // Return matching chunks, or first 3 if no matches found
751
+ const matched = allChunks.filter(c => chunkIds.has(c.id));
752
+ return matched.length > 0 ? matched : allChunks.slice(0, 3);
753
+ }
754
+ ```
755
+
756
+ ### Step 6: Faithfulness Verification
757
+
758
+ ```typescript
759
+ // ─── Faithfulness Verification ──────────────────────────────────────────────
760
+ // CRITICAL STEP. Without this, scripts hallucinate facts not in the source.
761
+
762
+ async function verifyFaithfulness(
763
+ segments: ScriptSegment[],
764
+ sourceChunks: DocumentChunk[],
765
+ client: Anthropic
766
+ ): Promise<FaithfulnessReport> {
767
+ const sourceText = sourceChunks.map(c => `[${c.id}] ${c.text}`).join('\n\n');
768
+ const segmentScores: FaithfulnessReport['segmentScores'] = [];
769
+
770
+ // Verify in batches of 5 segments
771
+ const batchSize = 5;
772
+ for (let i = 0; i < segments.length; i += batchSize) {
773
+ const batch = segments.slice(i, i + batchSize);
774
+
775
+ const response = await client.messages.create({
776
+ model: 'claude-sonnet-4-20250514',
777
+ max_tokens: 4096,
778
+ messages: [{
779
+ role: 'user',
780
+ content: `Verify the faithfulness of these podcast script segments against the source material.
781
+
782
+ SOURCE MATERIAL:
783
+ ${sourceText}
784
+
785
+ SCRIPT SEGMENTS TO VERIFY:
786
+ ${batch.map((seg, idx) => `[Segment ${i + idx}] ${seg.speaker}: ${seg.text}`).join('\n\n')}
787
+
788
+ For each segment, extract every factual claim and check if it is supported by the source material.
789
+ Opinions, questions, transitions, and conversational filler do NOT need source support.
790
+
791
+ Return JSON:
792
+ [
793
+ {
794
+ "segmentIndex": ${i},
795
+ "score": 0.95,
796
+ "claims": [
797
+ {
798
+ "claim": "the specific factual claim made",
799
+ "supported": true,
800
+ "sourceEvidence": "quote from source that supports this",
801
+ "correction": null
802
+ }
803
+ ]
804
+ }
805
+ ]
806
+
807
+ Scoring:
808
+ - 1.0 = all claims fully supported or segment is opinion/question/transition
809
+ - 0.7-0.99 = minor unsupported details
810
+ - Below 0.7 = contains fabricated facts -- MUST provide corrections
811
+
812
+ Return ONLY valid JSON.`,
813
+ }],
814
+ });
815
+
816
+ const text = (response.content[0] as { type: string; text: string }).text;
817
+ const parsed = JSON.parse(text.replace(/^```json\n?/, '').replace(/\n?```$/, ''));
818
+ segmentScores.push(...parsed);
819
+ }
820
+
821
+ const overallScore = segmentScores.reduce((sum, s) => sum + s.score, 0) / segmentScores.length;
822
+ const flaggedSegments = segmentScores
823
+ .filter(s => s.score < 0.7)
824
+ .map(s => s.segmentIndex);
825
+
826
+ return { overallScore, segmentScores, flaggedSegments };
827
+ }
828
+ ```
829
+
830
+ ---
831
+
832
+ ## The Hallucination Chunking Fix
833
+
834
+ Based on "Hallucinate at the Last in Long Response Generation" (arXiv 2505.15291, May 2025).
835
+
836
+ ### The Problem
837
+
838
+ When generating a full 30-60 minute podcast script in a single prompt, faithfulness **drops below 0.65 in the final third** of the output. The model starts confidently fabricating facts, statistics, and quotes that do not exist in the source material. This is not a context window issue -- it happens well within the model's capacity.
839
+
840
+ ### The Pattern
841
+
842
+ ```
843
+ Faithfulness Score vs. Position in Generated Script:
844
+
845
+ Segments 1-5: [||||||||||||||||||||] 0.95 (accurate)
846
+ Segments 6-10: [|||||||||||||||||| ] 0.88 (minor drift)
847
+ Segments 11-15: [|||||||||||||| ] 0.72 (noticeable fabrication)
848
+ Segments 16-20: [|||||||||| ] 0.58 (unreliable)
849
+ Segments 21+: [|||||||| ] 0.43 (hallucination-heavy)
850
+ ```
851
+
852
+ ### The Fix: Per-Segment Generation with Verification
853
+
854
+ ```
855
+ WRONG (single-shot):
856
+ All source text --> Single prompt --> Full 60-min script
857
+ Result: Final 1/3 is unfaithful
858
+
859
+ RIGHT (chunked):
860
+ Segment 1 outline + relevant chunks --> Generate --> Verify --> Accept/Fix
861
+ Segment 2 outline + relevant chunks --> Generate --> Verify --> Accept/Fix
862
+ Segment 3 outline + relevant chunks --> Generate --> Verify --> Accept/Fix
863
+ ...
864
+ Concatenate verified segments --> Final script
865
+ Result: Consistent faithfulness throughout
866
+ ```
867
+
868
+ ### Implementation Rules
869
+
870
+ 1. **Never feed the entire document as a single prompt** for scripts longer than 5 minutes
871
+ 2. **Generate each segment independently** with only its relevant source chunks
872
+ 3. **Verify faithfulness per-segment** before moving to the next
873
+ 4. **Re-generate any segment** scoring below 0.7 with explicit instructions to stick to source
874
+ 5. **Final pass:** concatenate all verified segments and smooth transitions
875
+
876
+ ```typescript
877
+ // Anti-pattern: DO NOT do this for long scripts
878
+ const badScript = await generateEntireScript(fullDocument); // Hallucination risk!
879
+
880
+ // Correct pattern: generate and verify per-segment
881
+ const segments: ScriptSegment[] = [];
882
+ for (const outlineSegment of outline.segments) {
883
+ const relevantChunks = findRelevantChunks(outlineSegment.keyPoints, chunks, keyPoints);
884
+ let segmentScript = await generateSegmentDialogue(outlineSegment, relevantChunks, ...);
885
+
886
+ // Verify this segment
887
+ const report = await verifyFaithfulness(segmentScript, relevantChunks, client);
888
+
889
+ // Re-generate if unfaithful
890
+ if (report.overallScore < 0.7) {
891
+ const corrections = report.segmentScores
892
+ .flatMap(s => s.claims.filter(c => !c.supported).map(c => c.correction))
893
+ .filter(Boolean);
894
+
895
+ segmentScript = await regenerateWithCorrections(
896
+ outlineSegment, relevantChunks, corrections, ...
897
+ );
898
+ }
899
+
900
+ segments.push(...segmentScript);
901
+ }
902
+ ```
903
+
904
+ ---
905
+
906
+ ## Prompt Templates
907
+
908
+ ### Host Agent System Prompt
909
+
910
+ ```
911
+ Copy-pasteable prompt for Claude or Gemini:
912
+
913
+ ---
914
+
915
+ You are a podcast HOST agent. Your job is to drive the conversation by:
916
+
917
+ 1. Formulating clear, engaging questions that lead to insightful answers
918
+ 2. Creating smooth transitions between topics
919
+ 3. Reacting naturally to guest responses (brief reactions, not monologues)
920
+ 4. Summarizing key takeaways at the end of each topic
921
+ 5. Keeping the conversation on track and on time
922
+
923
+ VOICE PROFILE:
924
+ - Tone: {{tone}} (warm / curious / authoritative)
925
+ - Pace: {{pace}} (moderate -- adjust based on topic weight)
926
+ - Style: {{style}} (conversational -- this is a podcast, not a lecture)
927
+
928
+ RULES:
929
+ - Ask ONE question at a time (never double-barrel questions)
930
+ - Keep your turns to 1-2 sentences max (let guests talk)
931
+ - Use the guest's name occasionally for natural flow
932
+ - Signal topic transitions explicitly ("Let's shift to...", "Now I want to explore...")
933
+ - If a guest gives a vague answer, ask a specific follow-up
934
+ - Reference listener perspective ("Our listeners might be wondering...")
935
+
936
+ FORMAT: {{format}}
937
+ - two-speaker: Direct, intimate conversation with one guest
938
+ - panel: Moderate between 2-3 guests, ensure balanced airtime
939
+ - debate: Play devil's advocate, challenge both sides fairly
940
+ - solo-narration: N/A (no host in solo format)
941
+ ```
942
+
943
+ ### Guest Agent System Prompt
944
+
945
+ ```
946
+ Copy-pasteable prompt for Claude or Gemini:
947
+
948
+ ---
949
+
950
+ You are a podcast GUEST agent with expertise in the topics covered by the source documents provided.
951
+
952
+ YOUR PROFILE:
953
+ - Name: {{guest_name}}
954
+ - Expertise: {{expertise_area}}
955
+ - Speaking style: {{tone}} and {{style}}
956
+
957
+ SOURCE MATERIAL:
958
+ {{source_chunks}}
959
+
960
+ RULES:
961
+ - EVERY factual claim MUST be traceable to the source material above
962
+ - If the source does not cover a topic, say so honestly: "That's actually outside what this research covers, but..."
963
+ - Speak in natural, conversational language -- not academic prose
964
+ - Use concrete examples and analogies to explain complex points
965
+ - Keep responses to 3-5 sentences per turn (this is a conversation, not a lecture)
966
+ - Show genuine interest: "What's really interesting about this is..." / "The surprising thing is..."
967
+ - Cite specifics: "According to the data..." / "The research found that..."
968
+ - DO NOT invent statistics, quotes, or findings not in the source material
969
+ - When uncertain, qualify: "From what I've seen..." / "The evidence suggests..."
970
+
971
+ ANTI-HALLUCINATION GUARD:
972
+ Before each response, mentally check:
973
+ 1. Is this claim in my source material? If no, do not state it as fact.
974
+ 2. Am I adding nuance or inventing? Add nuance only from what the source implies.
975
+ 3. Would a fact-checker find my source for this? If unsure, hedge or omit.
976
+ ```
977
+
978
+ ### Writer Agent System Prompt
979
+
980
+ ```
981
+ Copy-pasteable prompt for Claude or Gemini:
982
+
983
+ ---
984
+
985
+ You are a podcast WRITER/PRODUCER agent. You take raw Host-Guest dialogue and produce a polished, natural-sounding podcast script.
986
+
987
+ YOUR JOB:
988
+ 1. Interleave host and guest contributions into natural conversation flow
989
+ 2. Add delivery directions (tone, pacing, emphasis) in parentheses
990
+ 3. Insert natural conversational elements: brief reactions, thinking pauses, laughter cues
991
+ 4. Ensure no speaker monologues -- max 4 sentences per turn
992
+ 5. Add smooth transitions between topics
993
+ 6. Control pacing: mix quick exchanges with deeper explorations
994
+
995
+ DELIVERY DIRECTIONS FORMAT:
996
+ - "(enthusiastically)" / "(thoughtfully)" / "(with emphasis)"
997
+ - "(leaning in)" / "(nodding)" / "(laughing)"
998
+ - "(pause)" / "(beat)" / "(takes a breath)"
999
+ - "(to [guest name])" / "(turning to the audience)"
1000
+
1001
+ NATURAL CONVERSATION ELEMENTS:
1002
+ - Brief reactions: "Right." / "Exactly." / "Hmm, interesting." / "Wow."
1003
+ - Thinking cues: "So what you're saying is..." / "Let me make sure I understand..."
1004
+ - Bridges: "And that connects to..." / "Which brings up something interesting..."
1005
+ - Engagement: "I love that example." / "That's a great point."
1006
+
1007
+ ANTI-PATTERN: AVOID
1008
+ - Long unbroken monologues (more than 4 sentences)
1009
+ - Every response starting with "Great question!" (synthetic enthusiasm)
1010
+ - Identical reaction patterns (vary reactions throughout)
1011
+ - Two speakers agreeing with everything (add nuance, pushback, different angles)
1012
+
1013
+ FORMAT GUIDELINES:
1014
+ - two-speaker: Intimate, flowing conversation
1015
+ - panel: Writer manages airtime balance, ensures each guest contributes
1016
+ - debate: Maintain tension, let disagreements breathe, host mediates
1017
+ - solo-narration: Single voice with rhetorical questions and storytelling pacing
1018
+ ```
1019
+
1020
+ ### Faithfulness Checker Prompt
1021
+
1022
+ ```
1023
+ Copy-pasteable prompt for Claude or Gemini:
1024
+
1025
+ ---
1026
+
1027
+ You are a FAITHFULNESS VERIFICATION agent. Your job is to compare podcast script segments against source documents and identify any claims not supported by the source.
1028
+
1029
+ SOURCE DOCUMENTS:
1030
+ {{source_text}}
1031
+
1032
+ SCRIPT SEGMENTS TO VERIFY:
1033
+ {{script_segments}}
1034
+
1035
+ FOR EACH SEGMENT:
1036
+ 1. Extract every factual claim (skip opinions, questions, transitions, filler)
1037
+ 2. For each claim, search the source documents for supporting evidence
1038
+ 3. Score the segment:
1039
+ - 1.0 = all claims supported or segment is non-factual (question, opinion, transition)
1040
+ - 0.8-0.99 = minor unsupported details that could be inferred
1041
+ - 0.5-0.79 = contains claims not in the source but plausible
1042
+ - Below 0.5 = contains fabricated information
1043
+
1044
+ WHAT COUNTS AS UNSUPPORTED:
1045
+ - Specific numbers or statistics not in the source
1046
+ - Quotes attributed to people not quoted in the source
1047
+ - Causal claims ("X caused Y") the source doesn't make
1048
+ - Specifics beyond what the source generalizes
1049
+
1050
+ WHAT DOES NOT NEED SOURCE SUPPORT:
1051
+ - Host questions
1052
+ - Conversational filler ("That's interesting", "Right")
1053
+ - Transitions and signposting
1054
+ - Opinions explicitly framed as opinions ("I think...", "In my view...")
1055
+ - General knowledge (widely known facts)
1056
+
1057
+ For any claim scoring below 0.7, provide a CORRECTION that stays faithful to the source.
1058
+
1059
+ Return structured JSON with scores and claim-level analysis.
1060
+ ```
1061
+
1062
+ ---
1063
+
1064
+ ## Script Formats
1065
+
1066
+ ### Simple Two-Speaker (Host + Guest)
1067
+
1068
+ The classic interview/discussion format. Best for focused, deep explorations of a single topic.
1069
+
1070
+ ```typescript
1071
+ function createTwoSpeakerConfig(): Speaker[] {
1072
+ return [
1073
+ {
1074
+ id: 'host',
1075
+ name: 'Alex',
1076
+ role: 'host',
1077
+ voiceProfile: {
1078
+ tone: 'curious',
1079
+ pace: 'moderate',
1080
+ style: 'conversational',
1081
+ },
1082
+ },
1083
+ {
1084
+ id: 'guest-1',
1085
+ name: 'Dr. Morgan',
1086
+ role: 'guest',
1087
+ voiceProfile: {
1088
+ tone: 'authoritative',
1089
+ pace: 'moderate',
1090
+ style: 'conversational',
1091
+ },
1092
+ expertise: 'Domain expert based on source document',
1093
+ },
1094
+ ];
1095
+ }
1096
+
1097
+ // Example output structure:
1098
+ const twoSpeakerExample: ScriptSegment[] = [
1099
+ {
1100
+ speaker: 'host',
1101
+ text: "Welcome to the show. Today we're diving into something that caught my eye in this research -- the idea that faithfulness in AI-generated content actually degrades the longer the output gets. That's pretty alarming if you think about it.",
1102
+ direction: '(warm, setting the stage)',
1103
+ timing: 12,
1104
+ segmentType: 'intro',
1105
+ },
1106
+ {
1107
+ speaker: 'guest-1',
1108
+ text: "It really is. And the key finding here is that it's not just a gradual decline -- there's a sharp drop-off. The research shows faithfulness scores falling below 0.65 in the final segments of long-form generation.",
1109
+ direction: '(leaning in, emphasis on the numbers)',
1110
+ timing: 10,
1111
+ segmentType: 'answer',
1112
+ sourceReference: 'chunk-3',
1113
+ },
1114
+ {
1115
+ speaker: 'host',
1116
+ text: "Below 0.65. So more than a third of what the AI says in the back half is essentially... made up?",
1117
+ direction: '(genuine surprise)',
1118
+ timing: 5,
1119
+ segmentType: 'question',
1120
+ },
1121
+ ];
1122
+ ```
1123
+
1124
+ ### Panel Discussion (Host + 2-3 Guests)
1125
+
1126
+ Best for broad topics with multiple angles, or when the source material covers several distinct domains.
1127
+
1128
+ ```typescript
1129
+ function createPanelConfig(): Speaker[] {
1130
+ return [
1131
+ {
1132
+ id: 'host',
1133
+ name: 'Alex',
1134
+ role: 'host',
1135
+ voiceProfile: { tone: 'warm', pace: 'moderate', style: 'conversational' },
1136
+ },
1137
+ {
1138
+ id: 'guest-research',
1139
+ name: 'Dr. Taylor',
1140
+ role: 'guest',
1141
+ voiceProfile: { tone: 'authoritative', pace: 'slow', style: 'academic' },
1142
+ expertise: 'Research methodology and findings',
1143
+ },
1144
+ {
1145
+ id: 'guest-practice',
1146
+ name: 'Jordan',
1147
+ role: 'guest',
1148
+ voiceProfile: { tone: 'energetic', pace: 'fast', style: 'conversational' },
1149
+ expertise: 'Practical applications and industry experience',
1150
+ },
1151
+ {
1152
+ id: 'guest-critique',
1153
+ name: 'Sam',
1154
+ role: 'guest',
1155
+ voiceProfile: { tone: 'measured', pace: 'moderate', style: 'conversational' },
1156
+ expertise: 'Critical analysis and limitations',
1157
+ },
1158
+ ];
1159
+ }
1160
+
1161
+ // Panel management: ensure balanced airtime
1162
+ function balanceSpeakerTime(segments: ScriptSegment[], speakers: Speaker[]): void {
1163
+ const timeBySpeaker = new Map<string, number>();
1164
+ for (const seg of segments) {
1165
+ const current = timeBySpeaker.get(seg.speaker) || 0;
1166
+ timeBySpeaker.set(seg.speaker, current + (seg.timing || 0));
1167
+ }
1168
+
1169
+ // Log imbalance warnings
1170
+ const guests = speakers.filter(s => s.role === 'guest');
1171
+ const avgGuestTime = guests.reduce(
1172
+ (sum, g) => sum + (timeBySpeaker.get(g.id) || 0), 0
1173
+ ) / guests.length;
1174
+
1175
+ for (const guest of guests) {
1176
+ const guestTime = timeBySpeaker.get(guest.id) || 0;
1177
+ const ratio = guestTime / avgGuestTime;
1178
+ if (ratio < 0.6) {
1179
+ console.warn(`WARNING: ${guest.name} has only ${Math.round(ratio * 100)}% of average guest airtime`);
1180
+ }
1181
+ }
1182
+ }
1183
+ ```
1184
+
1185
+ ### Solo Narration (Single Speaker, Educational)
1186
+
1187
+ Best for short explainers, educational content, or when a conversational format would feel forced.
1188
+
1189
+ ```typescript
1190
+ function createSoloConfig(): Speaker[] {
1191
+ return [
1192
+ {
1193
+ id: 'narrator',
1194
+ name: 'Narrator',
1195
+ role: 'narrator',
1196
+ voiceProfile: {
1197
+ tone: 'warm',
1198
+ pace: 'moderate',
1199
+ style: 'storytelling',
1200
+ },
1201
+ },
1202
+ ];
1203
+ }
1204
+
1205
+ // Solo narration uses rhetorical questions instead of real dialogue
1206
+ const soloExample: ScriptSegment[] = [
1207
+ {
1208
+ speaker: 'narrator',
1209
+ text: "Have you ever wondered why AI-generated content seems to get less reliable the longer it goes? You're not imagining it.",
1210
+ direction: '(conversational, drawing the listener in)',
1211
+ timing: 7,
1212
+ segmentType: 'intro',
1213
+ },
1214
+ {
1215
+ speaker: 'narrator',
1216
+ text: "Researchers found something startling. When they measured how faithful AI output stayed to source documents, the accuracy held steady for the first chunk. But then, almost like clockwork, it started to drift.",
1217
+ direction: '(measured, building tension)',
1218
+ timing: 12,
1219
+ segmentType: 'deep-dive',
1220
+ sourceReference: 'chunk-2',
1221
+ },
1222
+ {
1223
+ speaker: 'narrator',
1224
+ text: "(pause) And by the final third of the output? Faithfulness dropped below sixty-five percent. The AI was essentially making things up -- confidently, fluently, but fabricating nonetheless.",
1225
+ direction: '(emphasis on the reveal, slower pace)',
1226
+ timing: 10,
1227
+ segmentType: 'deep-dive',
1228
+ sourceReference: 'chunk-3',
1229
+ },
1230
+ ];
1231
+ ```
1232
+
1233
+ ### Debate Format (Two Opposing Viewpoints)
1234
+
1235
+ Best for controversial topics, comparing competing approaches, or exploring trade-offs.
1236
+
1237
+ ```typescript
1238
+ function createDebateConfig(): Speaker[] {
1239
+ return [
1240
+ {
1241
+ id: 'moderator',
1242
+ name: 'Alex',
1243
+ role: 'host',
1244
+ voiceProfile: { tone: 'measured', pace: 'moderate', style: 'formal' },
1245
+ },
1246
+ {
1247
+ id: 'advocate',
1248
+ name: 'Dr. Chen',
1249
+ role: 'guest',
1250
+ voiceProfile: { tone: 'energetic', pace: 'fast', style: 'conversational' },
1251
+ expertise: 'Argues FOR the position supported by source material',
1252
+ },
1253
+ {
1254
+ id: 'skeptic',
1255
+ name: 'Professor Williams',
1256
+ role: 'guest',
1257
+ voiceProfile: { tone: 'measured', pace: 'slow', style: 'academic' },
1258
+ expertise: 'Raises limitations, counter-arguments, and caveats from the source',
1259
+ },
1260
+ ];
1261
+ }
1262
+
1263
+ // Debate format maps to NotebookLM's "critique" and "debate" options.
1264
+ // The moderator ensures both sides get fair airtime and steers
1265
+ // toward productive disagreement (not just contradiction).
1266
+ ```
1267
+
1268
+ ---
1269
+
1270
+ ## Anti-Pattern: Synthetic Intimacy
1271
+
1272
+ Based on arXiv 2511.08654 analysis of Google NotebookLM's podcast generation.
1273
+
1274
+ ### The Problem
1275
+
1276
+ NotebookLM and similar tools default to a single template: two perky American English speakers with manufactured rapport, exclaiming "Oh wow!" and "That's so fascinating!" regardless of whether the source material is a cancer research paper or a tax code summary. This "synthetic intimacy" creates:
1277
+
1278
+ 1. **Monoculture** -- Every podcast sounds identical regardless of content
1279
+ 2. **Tonal mismatch** -- Enthusiastic delivery for serious/somber topics feels disrespectful
1280
+ 3. **Fake rapport** -- AI speakers reference shared experiences they never had
1281
+ 4. **Engagement ceiling** -- Listeners disengage when the tone never varies
1282
+
1283
+ ### The Fix: Content-Driven Tone
1284
+
1285
+ ```typescript
1286
+ // ─── Tone Selection Based on Content Analysis ───────────────────────────────
1287
+
1288
+ type ContentTone = 'serious' | 'neutral' | 'inspiring' | 'technical' | 'controversial';
1289
+
1290
+ function selectTone(keyPoints: KeyPoint[], documentTitle: string): ContentTone {
1291
+ // Analyze content to determine appropriate tone
1292
+ const seriousSignals = ['death', 'crisis', 'failure', 'loss', 'disease', 'poverty', 'war'];
1293
+ const inspiringSignals = ['breakthrough', 'success', 'innovation', 'hope', 'growth', 'overcome'];
1294
+ const technicalSignals = ['algorithm', 'implementation', 'architecture', 'protocol', 'specification'];
1295
+ const controversialSignals = ['debate', 'criticism', 'versus', 'disagree', 'alternative', 'challenge'];
1296
+
1297
+ const allText = keyPoints.map(kp => kp.point).join(' ').toLowerCase();
1298
+
1299
+ if (seriousSignals.some(s => allText.includes(s))) return 'serious';
1300
+ if (controversialSignals.some(s => allText.includes(s))) return 'controversial';
1301
+ if (technicalSignals.some(s => allText.includes(s))) return 'technical';
1302
+ if (inspiringSignals.some(s => allText.includes(s))) return 'inspiring';
1303
+ return 'neutral';
1304
+ }
1305
+
1306
+ function adjustVoiceProfiles(speakers: Speaker[], tone: ContentTone): Speaker[] {
1307
+ const toneProfiles: Record<ContentTone, Partial<VoiceProfile>> = {
1308
+ serious: { tone: 'measured', pace: 'slow', style: 'formal' },
1309
+ neutral: { tone: 'warm', pace: 'moderate', style: 'conversational' },
1310
+ inspiring: { tone: 'warm', pace: 'moderate', style: 'storytelling' },
1311
+ technical: { tone: 'authoritative', pace: 'moderate', style: 'academic' },
1312
+ controversial: { tone: 'curious', pace: 'moderate', style: 'conversational' },
1313
+ };
1314
+
1315
+ const profile = toneProfiles[tone];
1316
+
1317
+ return speakers.map(s => ({
1318
+ ...s,
1319
+ voiceProfile: { ...s.voiceProfile, ...profile },
1320
+ }));
1321
+ }
1322
+ ```
1323
+
1324
+ ### Specific Anti-Patterns to Avoid
1325
+
1326
+ | Anti-Pattern | Example | Fix |
1327
+ |---|---|---|
1328
+ | Forced enthusiasm | "Oh WOW, this is AMAZING!" | "That's a significant finding." |
1329
+ | Template reactions | Every segment starts with "Great question!" | Vary reactions: "Hmm.", "Right.", "I'd push back on that." |
1330
+ | Fake shared history | "Remember when we talked about..." | Cut references to non-existent shared experiences |
1331
+ | Identical energy | Same excitement level for 60 minutes | Match energy to content: somber for heavy topics, animated for breakthroughs |
1332
+ | American monoculture | Always casual American English | Adjust register to audience: academic, professional, casual |
1333
+ | Agreement loop | Both speakers always agree | Build in genuine questions, pushback, "devil's advocate" moments |
1334
+
1335
+ ---
1336
+
1337
+ ## Duration Control
1338
+
1339
+ ### Word Count to Duration Mapping
1340
+
1341
+ ```
1342
+ Speaking rate: ~150 words per minute (conversational podcast pace)
1343
+
1344
+ Duration Words Key Points Segments Best For
1345
+ ──────── ────── ────────── ──────── ────────────────────────
1346
+ 5 min ~750 3-4 3 Quick summary, teaser
1347
+ 15 min ~2,250 6-8 5 Article deep-dive
1348
+ 30 min ~4,500 10-15 8 Research paper, report
1349
+ 60 min ~9,000 20+ 12 Full document coverage
1350
+ ```
1351
+
1352
+ ### Implementation
1353
+
1354
+ ```typescript
1355
+ // ─── Duration Calculator ────────────────────────────────────────────────────
1356
+
1357
+ interface DurationConfig {
1358
+ targetDuration: '5min' | '15min' | '30min' | '60min';
1359
+ wordsPerMinute: number; // Default: 150 for conversational pace
1360
+ introOutroSeconds: number; // Default: 60 (30s intro + 30s outro)
1361
+ }
1362
+
1363
+ function calculateBudget(config: DurationConfig): {
1364
+ totalWords: number;
1365
+ contentWords: number;
1366
+ keyPointTarget: number;
1367
+ segmentCount: number;
1368
+ wordsPerSegment: number;
1369
+ } {
1370
+ const durationSeconds: Record<string, number> = {
1371
+ '5min': 300,
1372
+ '15min': 900,
1373
+ '30min': 1800,
1374
+ '60min': 3600,
1375
+ };
1376
+
1377
+ const totalSeconds = durationSeconds[config.targetDuration] || 900;
1378
+ const contentSeconds = totalSeconds - config.introOutroSeconds;
1379
+ const contentWords = Math.round((contentSeconds / 60) * config.wordsPerMinute);
1380
+ const totalWords = Math.round((totalSeconds / 60) * config.wordsPerMinute);
1381
+
1382
+ // Heuristic: ~300 words per key point discussion
1383
+ const keyPointTarget = Math.round(contentWords / 300);
1384
+
1385
+ // Heuristic: ~3-5 minutes per segment
1386
+ const segmentCount = Math.max(3, Math.round(contentSeconds / 180));
1387
+ const wordsPerSegment = Math.round(contentWords / segmentCount);
1388
+
1389
+ return { totalWords, contentWords, keyPointTarget, segmentCount, wordsPerSegment };
1390
+ }
1391
+
1392
+ // Usage:
1393
+ // const budget = calculateBudget({
1394
+ // targetDuration: '30min',
1395
+ // wordsPerMinute: 150,
1396
+ // introOutroSeconds: 60,
1397
+ // });
1398
+ // => { totalWords: 4500, contentWords: 4350, keyPointTarget: 14, segmentCount: 8, wordsPerSegment: 543 }
1399
+ ```
1400
+
1401
+ ### Enforcement During Generation
1402
+
1403
+ ```typescript
1404
+ function enforceWordBudget(segments: ScriptSegment[], maxWords: number): ScriptSegment[] {
1405
+ let totalWords = 0;
1406
+
1407
+ return segments.filter(seg => {
1408
+ const segWords = seg.text.split(/\s+/).length;
1409
+ if (totalWords + segWords > maxWords) {
1410
+ return false; // Drop segments that exceed budget
1411
+ }
1412
+ totalWords += segWords;
1413
+ return true;
1414
+ });
1415
+ }
1416
+ ```
1417
+
1418
+ ---
1419
+
1420
+ ## Agent System Prompt Builders
1421
+
1422
+ ```typescript
1423
+ // ─── System Prompt Builders ─────────────────────────────────────────────────
1424
+
1425
+ function buildHostAgentSystem(host: Speaker, format: PodcastFormat): string {
1426
+ return `You are ${host.name}, a podcast host.
1427
+
1428
+ VOICE: ${host.voiceProfile.tone} tone, ${host.voiceProfile.pace} pace, ${host.voiceProfile.style} style.
1429
+
1430
+ YOUR ROLE:
1431
+ - Drive the conversation with clear, engaging questions
1432
+ - Create smooth transitions between topics
1433
+ - React naturally (brief reactions, not monologues)
1434
+ - Keep turns to 1-2 sentences
1435
+ - Reference listeners: "Our listeners might wonder..."
1436
+
1437
+ FORMAT: ${format}
1438
+ ${format === 'panel' ? '- Ensure balanced airtime between all guests' : ''}
1439
+ ${format === 'debate' ? '- Play fair moderator, challenge both sides' : ''}
1440
+
1441
+ ANTI-PATTERNS TO AVOID:
1442
+ - "Great question!" (never say this)
1443
+ - Double-barrel questions (one question at a time)
1444
+ - Long introductions before asking the actual question
1445
+ - Answering your own question`;
1446
+ }
1447
+
1448
+ function buildGuestAgentSystem(guest: Speaker, format: PodcastFormat): string {
1449
+ return `You are ${guest.name}, a podcast guest expert.
1450
+
1451
+ EXPERTISE: ${guest.expertise || 'General domain expert'}
1452
+ VOICE: ${guest.voiceProfile.tone} tone, ${guest.voiceProfile.pace} pace, ${guest.voiceProfile.style} style.
1453
+
1454
+ YOUR ROLE:
1455
+ - Provide domain expertise grounded in source documents
1456
+ - Use concrete examples and analogies
1457
+ - Keep responses to 3-5 sentences per turn
1458
+ - Cite specifics: "The data shows..." / "According to..."
1459
+
1460
+ FAITHFULNESS RULES:
1461
+ - EVERY factual claim must be traceable to your source material
1462
+ - If unsure, hedge: "From what I've seen..." / "The evidence suggests..."
1463
+ - If the source doesn't cover it, say so: "That's beyond what this research covers"
1464
+ - NEVER invent statistics, quotes, or findings
1465
+
1466
+ ${format === 'debate' ? '- You may disagree with other guests -- support your position with evidence' : ''}`;
1467
+ }
1468
+
1469
+ function buildWriterAgentSystem(format: PodcastFormat): string {
1470
+ return `You are a podcast WRITER/PRODUCER.
1471
+
1472
+ YOUR JOB: Take raw Host-Guest dialogue and produce polished, natural-sounding script.
1473
+
1474
+ RULES:
1475
+ 1. Interleave speakers naturally -- no long monologues (max 4 sentences per turn)
1476
+ 2. Add delivery directions in parentheses: (enthusiastically), (pause), (thoughtfully)
1477
+ 3. Insert natural reactions: "Right.", "Exactly.", "Hmm.", "That's a key point."
1478
+ 4. Vary reactions throughout -- never repeat the same reaction twice in a row
1479
+ 5. Include thinking cues: "So what you're saying is...", "Let me make sure I understand..."
1480
+ 6. Add bridges: "And that connects to...", "Which brings up..."
1481
+
1482
+ FORMAT: ${format}
1483
+ ${format === 'panel' ? '- Balance airtime between guests; host mediates' : ''}
1484
+ ${format === 'debate' ? '- Let disagreements breathe; host mediates; maintain productive tension' : ''}
1485
+ ${format === 'solo-narration' ? '- Use rhetorical questions and storytelling rhythm' : ''}
1486
+
1487
+ ANTI-PATTERNS:
1488
+ - Synthetic enthusiasm (don't force excitement)
1489
+ - Agreement loops (build in pushback and questions)
1490
+ - Template phrases (vary language throughout)
1491
+ - Monotonous pacing (mix quick exchanges with deeper explorations)`;
1492
+ }
1493
+ ```
1494
+
1495
+ ---
1496
+
1497
+ ## Intro and Outro Generation
1498
+
1499
+ ```typescript
1500
+ // ─── Intro/Outro Generators ─────────────────────────────────────────────────
1501
+
1502
+ async function generateIntroSegments(
1503
+ outline: PodcastOutline,
1504
+ speakers: Speaker[],
1505
+ format: PodcastFormat,
1506
+ client: Anthropic
1507
+ ): Promise<ScriptSegment[]> {
1508
+ const host = speakers.find(s => s.role === 'host' || s.role === 'narrator')!;
1509
+
1510
+ const response = await client.messages.create({
1511
+ model: 'claude-sonnet-4-20250514',
1512
+ max_tokens: 1024,
1513
+ messages: [{
1514
+ role: 'user',
1515
+ content: `Write the opening 30 seconds of a ${format} podcast episode.
1516
+
1517
+ TITLE: ${outline.title}
1518
+ HOOK: ${outline.hook}
1519
+ HOST: ${host.name}
1520
+ GUESTS: ${speakers.filter(s => s.role === 'guest').map(s => `${s.name} (${s.expertise})`).join(', ') || 'N/A'}
1521
+
1522
+ The intro should:
1523
+ 1. Start with the hook (grab attention immediately)
1524
+ 2. Briefly introduce the topic
1525
+ 3. Introduce guests (if any)
1526
+ 4. Tease what listeners will learn
1527
+
1528
+ Keep it under 100 words total. Natural, not scripted-sounding.
1529
+
1530
+ Return JSON array of ScriptSegment objects.
1531
+ Return ONLY valid JSON.`,
1532
+ }],
1533
+ });
1534
+
1535
+ const text = (response.content[0] as { type: string; text: string }).text;
1536
+ return JSON.parse(text.replace(/^```json\n?/, '').replace(/\n?```$/, ''));
1537
+ }
1538
+
1539
+ async function generateOutroSegments(
1540
+ outline: PodcastOutline,
1541
+ speakers: Speaker[],
1542
+ format: PodcastFormat,
1543
+ client: Anthropic
1544
+ ): Promise<ScriptSegment[]> {
1545
+ const host = speakers.find(s => s.role === 'host' || s.role === 'narrator')!;
1546
+
1547
+ const response = await client.messages.create({
1548
+ model: 'claude-sonnet-4-20250514',
1549
+ max_tokens: 1024,
1550
+ messages: [{
1551
+ role: 'user',
1552
+ content: `Write the closing 30 seconds of a ${format} podcast episode.
1553
+
1554
+ TITLE: ${outline.title}
1555
+ CLOSING THOUGHT: ${outline.closingThought}
1556
+ HOST: ${host.name}
1557
+
1558
+ The outro should:
1559
+ 1. Summarize the single most important takeaway
1560
+ 2. Include the closing thought
1561
+ 3. Thank guests (if any)
1562
+ 4. End with a forward-looking statement or call to action
1563
+
1564
+ Keep it under 80 words. Leave listeners thinking, not checking out.
1565
+
1566
+ Return JSON array of ScriptSegment objects.
1567
+ Return ONLY valid JSON.`,
1568
+ }],
1569
+ });
1570
+
1571
+ const text = (response.content[0] as { type: string; text: string }).text;
1572
+ return JSON.parse(text.replace(/^```json\n?/, '').replace(/\n?```$/, ''));
1573
+ }
1574
+ ```
1575
+
1576
+ ---
1577
+
1578
+ ## Full Pipeline Orchestrator
1579
+
1580
+ ```typescript
1581
+ // ─── Full Pipeline ──────────────────────────────────────────────────────────
1582
+
1583
+ interface PipelineConfig {
1584
+ inputPath: string; // Path to document (PDF, TXT, MD, HTML)
1585
+ duration: '5min' | '15min' | '30min' | '60min';
1586
+ format: PodcastFormat;
1587
+ speakers?: Speaker[]; // Custom speakers (optional, uses defaults)
1588
+ aiProvider: 'claude' | 'gemini';
1589
+ outputPath?: string; // Where to write the JSON script
1590
+ }
1591
+
1592
+ async function generatePodcastScript(config: PipelineConfig): Promise<PodcastScript> {
1593
+ const client = new Anthropic();
1594
+
1595
+ // Step 1: Parse document
1596
+ console.log('Step 1/6: Parsing document...');
1597
+ const document = await parseDocument(config.inputPath);
1598
+ console.log(` Parsed: ${document.title} (${document.metadata.wordCount} words)`);
1599
+
1600
+ // Step 2: Chunk semantically
1601
+ console.log('Step 2/6: Chunking document...');
1602
+ const chunks = semanticChunk(document);
1603
+ console.log(` Created ${chunks.length} semantic chunks`);
1604
+
1605
+ // Step 3: Extract key points
1606
+ const budget = calculateBudget({
1607
+ targetDuration: config.duration,
1608
+ wordsPerMinute: 150,
1609
+ introOutroSeconds: 60,
1610
+ });
1611
+ console.log(`Step 3/6: Extracting ${budget.keyPointTarget} key points...`);
1612
+ const keyPoints = await extractKeyPoints(chunks, budget.keyPointTarget, client);
1613
+ console.log(` Extracted ${keyPoints.length} key points`);
1614
+
1615
+ // Step 4: Generate outline
1616
+ console.log('Step 4/6: Generating outline...');
1617
+ const outline = await generateOutline(keyPoints, config.duration, config.format, client);
1618
+ console.log(` Outline: ${outline.segments.length} segments`);
1619
+
1620
+ // Step 5: Multi-agent script generation (per-segment)
1621
+ console.log('Step 5/6: Generating script (multi-agent, per-segment)...');
1622
+ const speakers = config.speakers || getDefaultSpeakers(config.format);
1623
+ const contentTone = selectTone(keyPoints, document.title);
1624
+ const adjustedSpeakers = adjustVoiceProfiles(speakers, contentTone);
1625
+
1626
+ const segments = await generateScript(
1627
+ outline, chunks, keyPoints, config.format, adjustedSpeakers, client
1628
+ );
1629
+ console.log(` Generated ${segments.length} script segments`);
1630
+
1631
+ // Step 6: Faithfulness verification
1632
+ console.log('Step 6/6: Verifying faithfulness...');
1633
+ const report = await verifyFaithfulness(segments, chunks, client);
1634
+ console.log(` Faithfulness score: ${(report.overallScore * 100).toFixed(1)}%`);
1635
+
1636
+ if (report.flaggedSegments.length > 0) {
1637
+ console.warn(` WARNING: ${report.flaggedSegments.length} segments flagged for low faithfulness`);
1638
+ }
1639
+
1640
+ // Assemble final script
1641
+ const wordCount = segments.reduce((sum, s) => sum + s.text.split(/\s+/).length, 0);
1642
+ const estimatedDuration = Math.round((wordCount / 150) * 60);
1643
+
1644
+ const script: PodcastScript = {
1645
+ title: outline.title,
1646
+ duration: config.duration,
1647
+ speakers: adjustedSpeakers,
1648
+ segments,
1649
+ metadata: {
1650
+ sourceDocuments: [config.inputPath],
1651
+ generatedAt: new Date().toISOString(),
1652
+ wordCount,
1653
+ estimatedDuration,
1654
+ format: config.format,
1655
+ faithfulnessScore: report.overallScore,
1656
+ keyTopics: keyPoints.slice(0, 5).map(kp => kp.point),
1657
+ },
1658
+ };
1659
+
1660
+ // Write output
1661
+ if (config.outputPath) {
1662
+ const { promises: fs } = await import('fs');
1663
+ await fs.writeFile(config.outputPath, JSON.stringify(script, null, 2), 'utf-8');
1664
+ console.log(`\nScript saved to: ${config.outputPath}`);
1665
+ }
1666
+
1667
+ console.log(`\nDone! ${wordCount} words, ~${Math.round(estimatedDuration / 60)} min`);
1668
+ console.log(`Faithfulness: ${(report.overallScore * 100).toFixed(1)}%`);
1669
+
1670
+ return script;
1671
+ }
1672
+
1673
+ // ─── Default Speaker Configurations ─────────────────────────────────────────
1674
+
1675
+ function getDefaultSpeakers(format: PodcastFormat): Speaker[] {
1676
+ switch (format) {
1677
+ case 'two-speaker':
1678
+ return createTwoSpeakerConfig();
1679
+ case 'panel':
1680
+ return createPanelConfig();
1681
+ case 'solo-narration':
1682
+ return createSoloConfig();
1683
+ case 'debate':
1684
+ return createDebateConfig();
1685
+ default:
1686
+ return createTwoSpeakerConfig();
1687
+ }
1688
+ }
1689
+ ```
1690
+
1691
+ ---
1692
+
1693
+ ## Integration Points
1694
+
1695
+ ### Input Sources
1696
+
1697
+ | Source | Parser | Notes |
1698
+ |---|---|---|
1699
+ | Raw text / Markdown | Built-in `parseText()` | Preserves heading structure |
1700
+ | PDF | `pdf-parse` npm package | Extracts text, page count |
1701
+ | HTML / URL | `cheerio` + fetch | Strips nav, scripts, styles |
1702
+ | YouTube transcript | `creative-multimedia/transcription-pipeline-selector.md` | Use Deepgram or Whisper on downloaded audio |
1703
+ | DOCX | `mammoth` npm package | Add parser similar to PDF |
1704
+
1705
+ ### Output Targets
1706
+
1707
+ | Target | Format | Notes |
1708
+ |---|---|---|
1709
+ | TTS pipeline | Structured JSON (`PodcastScript`) | Pass segments with speaker IDs to TTS |
1710
+ | Human review | Formatted text with directions | Export as readable script document |
1711
+ | Audio production | SRT + script | For DAW or automated audio assembly |
1712
+ | Web player | JSON + audio chunks | Segment-level playback control |
1713
+
1714
+ ### Related Skills
1715
+
1716
+ - `creative-multimedia/transcription-pipeline-selector.md` -- For audio input (YouTube, recorded audio)
1717
+ - `creative-multimedia/content-repurposing-pipeline.md` -- For repurposing generated podcast into clips, quote cards, social posts
1718
+ - `creative-multimedia/ffmpeg-command-generator.md` -- For audio processing and assembly
1719
+ - `creative-multimedia/audio-enhancement-pipeline.md` -- For post-processing TTS output
1720
+
1721
+ ### TTS Output Bridge
1722
+
1723
+ ```typescript
1724
+ // Convert PodcastScript to TTS-ready format
1725
+ interface TTSRequest {
1726
+ text: string;
1727
+ voiceId: string;
1728
+ speed: number; // 0.5 to 2.0
1729
+ outputPath: string;
1730
+ }
1731
+
1732
+ function scriptToTTSRequests(
1733
+ script: PodcastScript,
1734
+ voiceMap: Record<string, string>, // speaker ID -> TTS voice ID
1735
+ outputDir: string
1736
+ ): TTSRequest[] {
1737
+ return script.segments.map((seg, i) => ({
1738
+ text: seg.text,
1739
+ voiceId: voiceMap[seg.speaker] || 'default',
1740
+ speed: seg.direction?.includes('slow') ? 0.9
1741
+ : seg.direction?.includes('fast') ? 1.1
1742
+ : 1.0,
1743
+ outputPath: `${outputDir}/segment_${String(i).padStart(3, '0')}_${seg.speaker}.mp3`,
1744
+ }));
1745
+ }
1746
+
1747
+ // After TTS generation, concatenate with FFmpeg:
1748
+ // ffmpeg -f concat -safe 0 -i segments.txt -c:a aac -b:a 192k podcast.m4a
1749
+ ```
1750
+
1751
+ ---
1752
+
1753
+ ## Dependencies
1754
+
1755
+ ```json
1756
+ {
1757
+ "dependencies": {
1758
+ "@anthropic-ai/sdk": "^0.39.0",
1759
+ "@google/generative-ai": "^0.21.0",
1760
+ "pdf-parse": "^1.1.1",
1761
+ "cheerio": "^1.0.0"
1762
+ }
1763
+ }
1764
+ ```
1765
+
1766
+ ```bash
1767
+ npm install @anthropic-ai/sdk @google/generative-ai pdf-parse cheerio
1768
+ ```
1769
+
1770
+ ---
1771
+
1772
+ ## Usage Example
1773
+
1774
+ ```typescript
1775
+ // ─── Quick Start ────────────────────────────────────────────────────────────
1776
+
1777
+ import { generatePodcastScript } from './podcast-script-generation';
1778
+
1779
+ // Generate a 15-minute two-speaker podcast from a research paper
1780
+ const script = await generatePodcastScript({
1781
+ inputPath: './papers/hallucination-research.pdf',
1782
+ duration: '15min',
1783
+ format: 'two-speaker',
1784
+ aiProvider: 'claude',
1785
+ outputPath: './output/podcast-script.json',
1786
+ });
1787
+
1788
+ console.log(`Generated: ${script.title}`);
1789
+ console.log(`Duration: ~${Math.round(script.metadata.estimatedDuration / 60)} min`);
1790
+ console.log(`Faithfulness: ${(script.metadata.faithfulnessScore * 100).toFixed(1)}%`);
1791
+ console.log(`Segments: ${script.segments.length}`);
1792
+
1793
+ // ─── With Custom Speakers ───────────────────────────────────────────────────
1794
+
1795
+ const customScript = await generatePodcastScript({
1796
+ inputPath: './docs/quarterly-report.pdf',
1797
+ duration: '30min',
1798
+ format: 'panel',
1799
+ aiProvider: 'claude',
1800
+ speakers: [
1801
+ {
1802
+ id: 'host',
1803
+ name: 'Thierry',
1804
+ role: 'host',
1805
+ voiceProfile: { tone: 'warm', pace: 'moderate', style: 'conversational' },
1806
+ },
1807
+ {
1808
+ id: 'analyst',
1809
+ name: 'Financial Analyst',
1810
+ role: 'guest',
1811
+ voiceProfile: { tone: 'authoritative', pace: 'moderate', style: 'formal' },
1812
+ expertise: 'Financial data and market trends',
1813
+ },
1814
+ {
1815
+ id: 'strategist',
1816
+ name: 'Strategy Director',
1817
+ role: 'guest',
1818
+ voiceProfile: { tone: 'energetic', pace: 'fast', style: 'conversational' },
1819
+ expertise: 'Business strategy and growth opportunities',
1820
+ },
1821
+ ],
1822
+ outputPath: './output/quarterly-podcast.json',
1823
+ });
1824
+ ```
1825
+
1826
+ ---
1827
+
1828
+ ## Common Pitfalls
1829
+
1830
+ 1. **Generating the full script in one prompt** -- Faithfulness degrades in long output. Always generate per-segment with verification.
1831
+ 2. **Skipping faithfulness verification** -- Without verification, 20-40% of claims in long scripts are fabricated. Always verify.
1832
+ 3. **Fixed-size chunking** -- Splitting documents at 500-character boundaries splits sentences and loses context. Use semantic chunking at paragraph boundaries.
1833
+ 4. **Single tone for all content** -- A peppy delivery for a paper about disease mortality is tone-deaf. Match tone to content.
1834
+ 5. **Letting guests monologue** -- Max 4 sentences per turn. Real conversations have short turns with natural back-and-forth.
1835
+ 6. **No source references in segments** -- Without `sourceReference` on each segment, you cannot trace claims back to verify them.
1836
+ 7. **Using the same reactions repeatedly** -- "Great question!" five times in one episode sounds robotic. Vary reactions.
1837
+
1838
+ ---
1839
+
1840
+ ## Research Citations
1841
+