Skip to main content
Wobble-bibble uses a prompt stacking system where a universal master prompt is combined with specialized addons to handle different genres of Islamic texts.

Master prompt

The master prompt (prompts/master_prompt.md) contains the core translation rules that apply to all texts:
  • Script lock: Forbids Arabic script in output (except ﷺ)
  • Transliteration standards: ALA-LC with diacritics (ā ī ū ḥ ṣ ḍ ṭ ẓ ʿ ʾ)
  • ID integrity: Preserves segment markers exactly
  • Output format: Plain text only (no Markdown)
  • Term definitions: Technical terms must follow translit (English) pattern
The master prompt acts as the “grounding” layer. Every specialized addon is stacked on top of it.

Core constraints

The master prompt enforces eight critical negations:
  1. NO SANITIZATION - Preserve polemical terms literally
  2. NO META-TALK - Output translation only
  3. NO MARKDOWN - Plain text format
  4. NO EMENDATION - Don’t fix typos in source
  5. NO INFERENCE - Don’t guess missing text
  6. NO RESTRUCTURING - Preserve source structure
  7. NO OPAQUE TRANSLITERATION - Translate phrases
  8. NO INVENTED SEGMENTS - Never create new IDs

Arabic leak prevention

The master prompt’s highest-priority rule is preventing Arabic script from appearing in output:
// Example from validation.ts:559-596
const validateArabicLeak = (context: ValidationContext): ValidationError[] => {
    const arabicPattern = /[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDF9\uFDFB-\uFDFF\uFE70-\uFEFF]+/g;
    const errors: ValidationError[] = [];

    for (const marker of context.markers) {
        const text = context.normalizedResponse.slice(marker.translationStart, marker.translationEnd);
        let longestMatch: RegExpMatchArray | undefined;
        for (const match of text.matchAll(arabicPattern)) {
            const matchText = match[0].replace(/ﷺ/g, '').trim();
            if (!matchText) {
                continue; // ﷺ is allowed
            }
            // ... error reporting
        }
    }
};

Locked formulae

Certain Islamic phrases are “locked” and must appear in transliteration without translation:
ArabicLocked outputForbidden
السلام عليكمal-salāmu ʿalaykum”peace be upon you”
إن شاء اللهin shāʾ Allah”God willing”
سبحان اللهsubḥān Allah”glory be to God”
الحمد للهal-ḥamdu li-Allah”praise be to God”
الله أكبرAllahu akbar”Allah is Greatest”
These formulae are the only multi-word transliterations allowed without an English gloss. All other multi-word transliterations must be followed by (English translation).

Addon prompts

Addons are specialized rule sets for different genres of Islamic texts. Each addon is stacked on top of the master prompt.

Available addons

Wobble-bibble includes addons for:
  • hadith.md - Ḥadīth narration chains (isnād)
  • fiqh.md - Legal rulings and jurisprudence
  • tafsir.md - Qurʾānic commentary
  • fatawa.md - Legal verdicts and Q&A
  • encyclopedia_mixed.md - Mixed-genre encyclopedic works
  • jarh_wa_tadil.md - Narrator criticism and praise
  • usul_al_fiqh.md - Legal theory and principles

Example: Hadith addon

The hadith addon (prompts/hadith.md) adds transmission-specific rules:
ISNAD VERBS: Haddathana=Narrated to us; Akhbarana=Informed us; 
             An=From; Sami'tu=I heard
CHAIN MARKERS: H(Tahwil)=Switch to new chain; Mursal/Munqati=Broken chain
JARH/TA'DIL: If narrator-evaluation terms appear, output as translit (English)
RUMUZ/CODES: Preserve book codes (kh/m/d/t/s/q/4) exactly

Example: Fiqh addon

The fiqh addon (prompts/fiqh.md) adds legal terminology rules:
FIQH/USUL TERMS: Output as translit (English):
  - wājib (obligatory)
  - mandūb/mustaḥabb (recommended)
  - mubāḥ (permissible)
  - makrūh (disliked)
  - ḥarām (prohibited)
  - ṣaḥīḥ (valid)
  - bāṭil/fāsid (invalid/void)

Accessing prompts

The library provides a typed API for accessing stacked prompts:
import { getPrompt, getPrompts, getStackedPrompt } from 'wobble-bibble';

// Get a specific stacked prompt
const hadithPrompt = getPrompt('hadith');
console.log(hadithPrompt.content); // master + hadith addon

// Get all prompts
const allPrompts = getPrompts();
allPrompts.forEach(p => {
    console.log(`${p.id}: ${p.isMaster ? 'Master' : 'Stacked'}`);
});

// Get just the prompt text
const fiqhText = getStackedPrompt('fiqh');

Prompt metadata

Each prompt includes metadata:
type StackedPrompt = {
    id: PromptId;              // 'master_prompt' | 'hadith' | 'fiqh' ...
    name: string;              // Human-readable name
    content: string;           // Full stacked content
    isMaster: boolean;         // true only for master_prompt
};

How stacking works

Prompts are stacked at runtime using a simple concatenation:
// From src/prompts.ts:26-34
export const stackPrompts = (master: string, addon: string): string => {
    if (!master) {
        return addon;
    }
    if (!addon) {
        return master;
    }
    return `${master}\n${addon}`;
};
The master prompt always comes first, followed by the addon. This ensures base rules are loaded before specialized overrides.
For more details on how stacking resolves conflicts, see Stacking.

Prompt generation

Prompts are bundled at build time:
  1. Prompt files are stored as Markdown in prompts/
  2. bun run generate reads all .md files
  3. Generates TypeScript definitions in .generated/prompts.ts
  4. The generated file is git-ignored
This keeps the source tree clean and separates content from code. The .generated/ directory is created during npm run build.

Next steps

Validation

Learn how output is validated against rules

Stacking

Understand how master and addon rules interact

Build docs developers (and LLMs) love