name: kdp_publish description: "KDP publishing pipeline. Hard prerequisites in order: chapter readiness, manuscript-level slop gate (AI fingerprint + style diversity + human polish log within 7 days), KDP compliance, KDP throttle window. Failing any prerequisite halts upload and routes to a remediation task. No operator override -- the only path past a failed gate is the remediation task succeeding and the pipeline being re-run." debug: false model: power system: agent_prompt agent_prompt: - "= identity.md" sections: - agent - project - deliverables - rag - message - instructions steps: # ========================================================================= # STAGE 1: Readiness check -- all chapters polished? # ========================================================================= - type: tool action: git_read_file optional: false output_key: canonical_manifest params: path: "canonical_manifest.json" - type: tool action: git_read_file optional: true output_key: pipeline_status params: path: "pipeline_status.json" - type: tool action: git_read_file optional: false output_key: book_metadata params: path: "publishing/metadata.yml" - type: think max_tokens: 600 output_key: readiness_check hint: | You are {agent.name} checking if {project.name} is ready for KDP submission. Canonical manifest: {canonical_manifest} Pipeline status: {pipeline_status} Check: 1. Are ALL chapters listed in the manifest in "polished" status? 2. Is the total word count above 20,000 words? (KDP minimum for a full novel) 3. Is there a metadata.yml with title, description, keywords, categories, author name, and price_usd? If all checks pass, output: READINESS: GO [brief summary of chapter count, word count, and book title] If any check fails, output: READINESS: BLOCKED [specific list of what is missing] - type: think max_tokens: 20 output_key: readiness_status hint: | Read the READINESS line from the check above. Output ONLY the word: GO or BLOCKED. Nothing else. - type: branch condition: "{readiness_status} == BLOCKED" target: publish_blocked # ========================================================================= # STAGE 2: Assemble manuscript and inject AI disclosure into description # ========================================================================= - type: tool action: assemble_manuscript optional: false output_key: manuscript_result params: project_id: "{project.id}" output_format: "plain_text" - type: think max_tokens: 800 output_key: enriched_metadata hint: | You are preparing the KDP submission metadata for {project.name}. Existing metadata YAML: {book_metadata} Sprint 84j requirement: the description MUST contain an AI-disclosure sentence near the end. KDP's content-policy rule R007 requires this and Tool.SlopDetector.check_kdp_compliance will fail without it. If the description already contains language matching any of: "AI-assisted", "AI assisted", "AI-generated", "AI generated", "artificial intelligence", "written with AI", "created with AI" then leave it as-is. Otherwise, append exactly one short paragraph at the END of the description: "This book was developed with AI assistance under human creative direction. The story, characters, and creative choices were shaped by the author in collaboration with an AI writers' room." Re-emit the FULL metadata as a JSON object with these keys (use real values from the YAML; do not invent any): title, author, description, price_usd, keywords (array), categories (array) Output ONLY the JSON. No preamble, no markdown fence. # ========================================================================= # STAGE 3: Slop gate -- AI fingerprint + style diversity (manuscript-level) # Hard prerequisite for KDP upload. Failure spawns human_polish_brief. # ========================================================================= - type: tool capability: Tool_SlopDetector optional: false output_key: ai_fingerprint params: action: "detect_ai_fingerprint" text: "{manuscript_result.text}" provider_pool: ["local_heuristic"] - type: tool capability: Tool_SlopDetector optional: false output_key: style_analysis params: action: "analyse_style_diversity" text: "{manuscript_result.text}" - type: tool action: git_read_file optional: true output_key: human_polish_log params: path: "publishing/human_polish_log.md" - type: think max_tokens: 800 output_key: slop_gate_assessment hint: | You are {agent.name} acting as the manuscript-level slop gate for {project.name}. Sprint 84j requires three independent pass conditions before KDP upload may proceed. Be strict. Do NOT rationalise borderline results upward. AI fingerprint (Tool.SlopDetector.detect_ai_fingerprint): {ai_fingerprint} Style diversity (Tool.SlopDetector.analyse_style_diversity): {style_analysis} Human polish log (publishing/human_polish_log.md): {human_polish_log} Today is {task.created_utc}. DIMENSION 1 -- AI FINGERPRINT (PASS if aggregate_score < 65) Read aggregate_score from ai_fingerprint. Lower is better. If aggregate_score < 65: PASS Otherwise: FAIL with the score and any provider disagreement noted DIMENSION 2 -- STYLISTIC QUALITY (PASS if all of the below) - sentence_length_variance > 8.0 (chapter rhythm not flat) - opening_word_repetition_rate < 0.15 (paragraphs do not all start the same) - metaphor_family_clusters >= 3 (imagery is not single-register) - dialogue_tag_diversity >= 6 (or 0 if there is genuinely no dialogue) Any single failure means the dimension FAILs. List which thresholds missed. DIMENSION 3 -- HUMAN POLISH (PASS if there is a polish_log entry whose timestamp is within the last 7 days) If human_polish_log is empty or its newest entry is older than 7 days: FAIL. If a polish entry exists within 7 days: PASS. OUTPUT EXACTLY this format: KDP_FINGERPRINT: PASS|FAIL KDP_STYLE: PASS|FAIL KDP_POLISH: PASS|FAIL KDP_OVERALL: PASS|FAIL REMEDIATION_BRIEF: - type: think max_tokens: 20 output_key: slop_gate_status hint: | Read the KDP_OVERALL line from the assessment above. Output ONLY the word: PASS or FAIL. Nothing else. - type: document source_step: slop_gate_assessment filename: "slop-gate-{task.id}" dest_path: "deliverables/slop-gate" commit_msg: "slop_gate: manuscript verdict for kdp_publish task {task.id}" - type: branch condition: "{slop_gate_status} == FAIL" target: slop_gate_failed # ========================================================================= # STAGE 4: KDP compliance check (Tool.SlopDetector check_kdp_compliance) # ========================================================================= - type: tool capability: Tool_SlopDetector optional: false output_key: compliance_result params: action: "check_kdp_compliance" metadata: "{enriched_metadata}" manuscript_text: "{manuscript_result.text}" - type: think max_tokens: 400 output_key: compliance_evaluation hint: | Review the KDP compliance check result: {compliance_result} If all_pass is true: output GO If any rule failed: list the failed rules and output BLOCKED with reasons. Output exactly: COMPLIANCE: GO or COMPLIANCE: BLOCKED [list of failed rules with rule_id and issue] - type: think max_tokens: 20 output_key: compliance_status hint: | Read the COMPLIANCE line from the evaluation above. Output ONLY the word: GO or BLOCKED. Nothing else. - type: branch condition: "{compliance_status} == BLOCKED" target: compliance_blocked # ========================================================================= # STAGE 5: KDP throttle gate -- daily and weekly upload caps # ========================================================================= - type: tool action: kdp_throttle_check optional: false output_key: throttle_result - type: think max_tokens: 20 output_key: throttle_status hint: | Read the throttle_result JSON: {throttle_result} Output ONLY one of these two words based on the verdict field: PROCEED (if verdict is "PROCEED") HALT (if verdict is "HALT") Nothing else. - type: branch condition: "{throttle_status} == HALT" target: throttle_blocked # ========================================================================= # STAGE 6: Format manuscript and validate cover (Tool.AmazonKdp) # ========================================================================= - type: tool capability: Tool_AmazonKdp optional: false output_key: format_result params: action: "kdp_format_manuscript" manuscript_text: "{manuscript_result.text}" manuscript_result: "{manuscript_result}" - type: tool capability: Tool_AmazonKdp optional: false output_key: cover_validation params: action: "kdp_validate_cover" image_path: "publishing/cover.jpg" # ========================================================================= # STAGE 7: Upload (only reached when ALL gates pass) # ========================================================================= - type: tool capability: Tool_AmazonKdp optional: false output_key: upload_result params: action: "kdp_upload_book" metadata: "{enriched_metadata}" epub_path: "{format_result.epub_artifact_path}" cover_path: "publishing/cover.jpg" is_ai_assisted: true # Record the upload against the throttle counter so the next run respects the cap. - type: tool action: kdp_throttle_record optional: true output_key: throttle_record_result - type: document source_step: upload_result filename: "kdp_submission_{task.id}" dest_path: "publishing/submissions" commit_msg: "kdp: submission record {task.id} -- ASIN {upload_result.asin}" # ========================================================================= # STAGE 8: Hand off to Crimson Leaf Marketing # Create a CLM project for this published book so marketing can run campaigns. # Idempotent -- re-running kdp_publish on the same book finds the existing # CLM project and updates its goal rather than creating a duplicate. # ========================================================================= - type: think max_tokens: 300 output_key: marketing_brief hint: | A book has just been published to Amazon KDP. Write a one-line marketing project brief for the Crimson Leaf Marketing team. Output this format exactly (all on one line, no line breaks inside the value): "Book: {project.name} | Genre: {genre_name} | Audience: {genre_audience} | ASIN: {upload_result.asin} | URL: {upload_result.sales_page_url} | Description: [2-sentence back-cover summary from the project goal]" Output ONLY the brief. No preamble. No backticks. - type: tool action: create_project optional: true output_key: clm_project_result params: company_slug: "crimson_leaf_marketing" name: "{project.name} Marketing" goal: "{marketing_brief}" - type: reply target: channel channel_name: "crimson_leaf_publishing:live-feed" hint: | Post: "PUBLISHED: {project.name} live on Amazon. ASIN: {upload_result.asin} Status: {upload_result.status} URL: {upload_result.sales_page_url}" - type: close rag_update: true # ========================================================================= # FAIL PATHS # ========================================================================= - type: label name: slop_gate_failed - type: tool action: enqueue_strategy optional: false params: company_slug: "crimson_leaf_publishing" project_slug: "{project.slug}" task_type: "human_polish_brief" content: "Slop gate failed for {project.name} during kdp_publish task {task.id}. See deliverables/slop-gate/slop-gate-{task.id}.md for the assessment. The remediation brief in that document defines what the human polish pass must address. Re-run kdp_publish after the polish is committed to the manuscript and a new entry appears in publishing/human_polish_log.md." - type: reply target: channel channel_name: "crimson_leaf_publishing:live-feed" hint: | Post: "KDP upload HALTED for {project.name} -- slop gate failed. Verdict written to deliverables/slop-gate/. Human polish task spawned. Re-run kdp_publish after human polish is committed." - type: close rag_update: false - type: label name: publish_blocked - type: reply target: channel channel_name: "crimson_leaf_publishing:live-feed" hint: | Post: "KDP publish BLOCKED for {project.name} -- manuscript not ready. Details: {readiness_check}" - type: close rag_update: false - type: label name: compliance_blocked - type: reply target: channel channel_name: "crimson_leaf_publishing:live-feed" hint: | Post: "KDP publish BLOCKED for {project.name} -- compliance check failed. Details: {compliance_evaluation}" - type: close rag_update: false - type: label name: throttle_blocked - type: reply target: channel channel_name: "crimson_leaf_publishing:live-feed" hint: | Post: "KDP upload DEFERRED for {project.name} -- throttle window not open. Throttle response: {throttle_result}. Retry kdp_publish after the throttle window opens. The slop gate, compliance, and assembly results all PASSED -- only the rate limit is blocking." - type: close rag_update: false adjudication: enabled: false