170 lines
9.2 KiB
Python
170 lines
9.2 KiB
Python
#!/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!") |