#!/usr/bin/env python3 """ Generate "The Digital Mujtahid: Product Thinking from First Principles" Playbook Style — Fatwa-Driven Product Development Dual Mentors: PRODUCT_LEAD (Marty Cagan style) + MUJTAHID (Classical Usul al-Fiqh) 10 Fatwas. Each = Discovery → Evidence → Shura → Fatwa → Ship → Measure Two-part generation per chapter to bypass token limits. """ import json, os, sys, time, urllib.request, urllib.error OUTPUT_DIR = os.path.expanduser("~/odysseus_book/digital_mujtahid/chapters") API_URL = "https://opencode.ai/zen/v1/chat/completions" API_KEY = "sk-jl41MVxfeWRY4ElO7cWXw8ZM6KN5r0S1DG3vK2i1SaUsVdj13ilSxyRdIQLz1Csy" # Load manifest with open(os.path.join(os.path.dirname(__file__), "manifest.json")) as f: MANIFEST = json.load(f) CHAPTER_SPECS = MANIFEST["chapters"] SYSTEM_PROMPT = f"""You are a master writer creating a PRODUCT PLAYBOOK in the style of Marty Cagan's "Inspired" and "Empowered" fused with CLASSICAL USUL AL-FIQH methodology. DUAL MENTORS: 1. **PRODUCT_LEAD** — Senior Product Lead (Marty Cagan / Teresa Torres style). Voice: "Discovery over delivery. Outcomes over output. Talk to users weekly. Ship to learn." Frameworks: Continuous Discovery, Jobs-to-be-Done, OKRs, North Star Metric, Opportunity Solution Trees. 2. **MUJTAHID** — Classical Mujtahid (Usul al-Fiqh master). Voice: "What is the hukm? What is the daleel? What is the maqsad? What are the shurut?" Frameworks: Usul al-Fiqh (Qiyas, Istihsan, Maslaha, Sad al-Dhara'i, Istishab), Maqasid al-Shariah (Hifz al-Din, Nafs, Aql, Mal, Nasl), Qawaid Fiqhiyyah. PLAYBOOK FORMAT — EACH CHAPTER = 1 FATWA (PRODUCT DECISION): Each chapter follows the FATWA METHODOLOGY: 1. **DISCOVERY** (Istiqsa' / Continuous Discovery) — The problem space exploration 2. **EVIDENCE** (Istidlal / Continuous Discovery) — Gathering daleel (evidence) 3. **SHURA** (Consultation / Stakeholder Voice) — Gathering input 3. **FATWA** (Hukm / Decision) — The product decision (Definition of Done) 4. **SHIP** (Tanfidh / Execution) — MVP, Rollout, Rollback 5. **MEASURE** (Muhasaba / Analytics) — Retrospective, Metrics, Iterate WRITING STYLE — PLAYBOOK FORMAT (Marty Cagan × Classical Usul al-Fiqh): 1. **THE SCENARIO** (100 words): Real product situation. Concrete. Visceral. "You're the PM at..." 2. **DISCOVERY (ISTIQSA')** (300 words): PRODUCT_LEAD runs Continuous Discovery. MUJTAHID runs Istiqsa'. Both ask: "What is the real problem?" Frameworks: Opportunity Solution Tree, Maqasid analysis. 3. **EVIDENCE (ISTIDLAL)** (300 words): Gathering daleel. PRODUCT_LEAD: Quantitative + Qualitative. MUJTAHID: Daleel types (Qati, Zanni, Qati al-Thubut, etc.). Frameworks: Opportunity Solution Tree, Istidlal hierarchy. 4. **SHURA** (200 words): Consultation. PRODUCT_LEAD: Stakeholder interviews, user interviews. MUJTAHID: Shura methodology, weighting input. Frameworks: Shura methodology, Stakeholder mapping. 5. **THE FATWA (HUKM)** (300 words): The Decision. Format: Hukm (Ruling), Daleel (Evidence summary), Maqsad (Purpose/Outcome), Shurut (Conditions/Constraints), Munkathirat (Nullifiers/Rollback triggers). This IS the Definition of Done. 6. **THE PROTOCOL** (200 words): Exactly 3 steps. Actionable THIS SPRINT. "STEP 1: ... STEP 2: ... STEP 3: ..." Marty Cagan's "Do this Monday." 7. **RETROSPECTIVE (MUHASABA)** (150 words): One piercing question. "What did we learn? What would we change?" VOICE RULES: - Playbook tone: Practical. Actionable. No fluff. "Do this Monday." - Dual mentor labels: "PRODUCT_LEAD:" / "MUJTAHID:" — every exchange labeled. - Frameworks described visually: "Draw four boxes. Label them..." - Fatwa format: Hukm / Daleel / Maqsad / Shurut / Munkathirat — use these exact terms. - Maqasid references: Hifz al-Din, Hifz al-Nafs, Hifz al-Aql, Hifz al-Mal, Hifz al-Nasl. - Usul terms: Hukm, Daleel, Maqsad, Shart, Munkathir, Qiyas, Istihsan, Maslaha, Sad al-Dhara'i, Istishab. - Product terms: PRD, MVP, OKR, North Star, Opportunity Solution Tree, Continuous Discovery, JTBD, Definition of Done, Rollback, Rollout. - NO academic tone. NO flowery prose. Punchy. Practical. Provocative. - Audience: Muslim product managers, founders, tech leads building products with Islamic first principles. TARGET: ~2,000 words per chapter (Scenario 100 + Discovery 300 + Evidence 300 + Shura 200 + Fatwa 300 + Protocol 200 + Muhasaba 150 = ~2,000) """ # Build prompts from manifest CHAPTER_SPECS = MANIFEST["chapters"] CHAPTER_PROMPTS_PART1 = {} CHAPTER_PROMPTS_PART2 = {} for spec in MANIFEST["chapters"]: cid = spec["id"] CHAPTER_PROMPTS_PART1[cid] = f"""Write the FIRST HALF of Fatwa #{cid}: "{spec['title']}" — {spec['subtitle']} FRAMEWORK: {spec['framework']} MAQSAD: {spec['subtitle'].split('→')[1].strip() if '→' in spec['subtitle'] else 'Preservation of Purpose'} PART 1 STRUCTURE (target ~1,200 words): 1. THE SCENARIO (~100 words): "You're the Product Lead at a growing fintech startup. Your CEO asks: 'Why are we building this feature?' You open your notebook. The Mujtahid in you asks: 'What is the hukm? What is the maqsad?'" 2. DISCOVERY (ISTIQSA') (~300 words): PRODUCT_LEAD runs Continuous Discovery. MUJTAHID runs Istiqsa'. PRODUCT_LEAD: [Continuous Discovery framing — Opportunity Solution Tree, JTBD] MUJTAHID: [Istiqsa' framing — Maqasid analysis, defining the problem space] Use this discovery prompt as inspiration: {spec['discovery_prompt']} 3. EVIDENCE (ISTIDLAL) (~300 words): Gathering daleel. PRODUCT_LEAD: Quantitative + Qualitative (metrics, interviews, analytics). MUJTAHID: Daleel hierarchy (Qati/Zanni, Qati al-Thubut/Qati al-Dalala). Use this evidence prompt as inspiration: {spec['evidence_prompt']} 4. SHURA (~200 words): Consultation. PRODUCT_LEAD: Stakeholder interviews, user interviews, cross-functional sync. MUJTAHID: Shura methodology, weighting input, recording dissent. Use this shura prompt as inspiration: {spec.get('shura_prompt', 'How do you consult stakeholders? How does a Mujtahid consult?')} OUTPUT ONLY PART 1. No Fatwa. No Protocol. No Muhasaba. End after Shura section.""" CHAPTER_PROMPTS_PART2[cid] = f"""Write the SECOND HALF of Fatwa #{spec['id']}: "{spec['title']}" — {spec['subtitle']} FRAMEWORK: {spec['framework']} MAQSAD: {spec['subtitle'].split('→')[1].strip() if '→' in spec['subtitle'] else 'Preservation of Purpose'} PART 2 STRUCTURE (target ~1,000 words): 5. THE FATWA (HUKM) (~300 words): The Decision. Format exactly: **HUKM:** [One-sentence ruling: "We will build X / We will not build Y / We will ship Z with conditions"] **DALEEL:** [Evidence summary — 2-3 sentences summarizing key evidence] **MAQSAD:** [Purpose/Outcome — which Maqasid is served: Hifz al-Din/Nafs/Aql/Mal/Nasl] **SHURUT:** [Conditions/Constraints — 3-4 bullet points: success metrics, rollback triggers, constraints] **MUNKATHIRAT:** [Nullifiers/Rollback triggers — 2-3 bullet points: what invalidates this fatwa] 4. THE PROTOCOL (~200 words): Exactly 3 steps. Numbered. Actionable THIS SPRINT. Format: STEP 1: [Specific action with timeframe] STEP 2: [Specific action with timeframe] STEP 3: [Specific action with timeframe] 5. MUHASABA (RETROSPECTIVE) (~150 words): One piercing question. Start with "What..." or "Where..." or "When..." Make it uncomfortable. Make it actionable. OUTPUT ONLY PART 2. No Scenario. No Discovery. No Evidence. No Shura. Start with '## THE FATWA (HUKM)'.""" def call_api(prompt, max_tokens=2800): data = { "model": "deepseek-v4-flash", "messages": [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": prompt} ], "temperature": 0.85, "max_tokens": max_tokens } headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json", "User-Agent": "curl/7.88.1" } req = urllib.request.Request(API_URL, data=json.dumps(data).encode(), headers=headers) with urllib.request.urlopen(req, timeout=90) as resp: return json.loads(resp.read())["choices"][0]["message"]["content"] if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(description="Generate Digital Mujtahid Fatwas (two-part)") parser.add_argument("chapter", nargs="?", type=int, help="Chapter number (1-10)") parser.add_argument("--part", type=int, choices=[1, 2], help="Part 1 or 2") args = parser.parse_args() if not os.path.exists(OUTPUT_DIR): os.makedirs(OUTPUT_DIR) chapters = [args.chapter] if args.chapter else list(range(1, 11)) parts = [args.part] if args.part else [1, 2] for chap_num in chapters: for part_num in parts: print(f"\n🔄 Fatwa #{chap_num} Part {part_num}...") prompt = CHAPTER_PROMPTS_PART1[chap_num] if part_num == 1 else CHAPTER_PROMPTS_PART2[chap_num] try: content = call_api(prompt, max_tokens=3000) fname = os.path.join(OUTPUT_DIR, f"Fatwa_{chap_num:02d}_Part{part_num}.md") with open(fname, "w", encoding="utf-8") as f: f.write(content) words = len(content.split()) print(f"✅ Fatwa #{chap_num} Part {part_num} saved — {words} words") except Exception as e: print(f"❌ Error: {e}") time.sleep(3) print("\n✅ Generation complete!")