> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rumik.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# prompting silk muga 1

> how to steer silk muga 1 with tones and inline events.

export const ToneMatrix = () => {
  const ROWS = [["[happy]", "best", "best", "avoid"], ["[excited]", "best", "ok", "avoid"], ["[sad]", "avoid", "avoid", "best"], ["[angry]", "avoid", "rare", "ok"], ["[neutral]", "ok", "avoid", "ok"], ["[whisper]", "avoid", "ok", "ok"]];
  const SYM = {
    best: {
      s: "✓✓",
      c: "text-green-600 dark:text-green-400 font-semibold"
    },
    ok: {
      s: "✓",
      c: "text-green-600 dark:text-green-400"
    },
    rare: {
      s: "~",
      c: "text-amber-500 dark:text-amber-400"
    },
    avoid: {
      s: "✗",
      c: "text-red-500 dark:text-red-400"
    }
  };
  const head = "px-3 py-2 text-center font-mono text-xs font-semibold text-gray-500 dark:text-gray-400";
  const cell = "px-3 py-2 text-center text-base";
  return <div className="not-prose my-4">
      <div className="overflow-x-auto rounded-xl border border-gray-200 dark:border-white/10">
        <table className="w-full border-collapse text-sm">
          <thead>
            <tr className="border-b border-gray-200 dark:border-white/10">
              <th className="pl-5 pr-3 py-2 text-left font-mono text-xs font-semibold text-gray-500 dark:text-gray-400">tone</th>
              <th className={head}>{"<laugh>"}</th>
              <th className={head}>{"<chuckle>"}</th>
              <th className={head}>{"<sigh>"}</th>
            </tr>
          </thead>
          <tbody>
            {ROWS.map((r, i) => <tr key={r[0]} className={i < ROWS.length - 1 ? "border-b border-gray-100 dark:border-white/5" : ""}>
                <td className="pl-5 pr-3 py-2 font-mono text-xs text-gray-700 dark:text-gray-300">
                  {r[0]}
                </td>
                {r.slice(1).map((k, j) => <td key={j} className={cell + " " + SYM[k].c}>
                    {SYM[k].s}
                  </td>)}
              </tr>)}
          </tbody>
        </table>
      </div>
      <p className="mt-2 text-xs text-gray-500 dark:text-gray-400">
        <span className="text-green-600 dark:text-green-400">{"✓✓"}</span> best
        {"  ·  "}
        <span className="text-green-600 dark:text-green-400">{"✓"}</span> ok
        {"  ·  "}
        <span className="text-amber-500 dark:text-amber-400">~</span> rare
        {"  ·  "}
        <span className="text-red-500 dark:text-red-400">{"✗"}</span> avoid
      </p>
    </div>;
};

export const VoiceSample = ({tone, label, note, description, text, src}) => {
  const TONE_PILL = {
    happy: "bg-amber-100 text-amber-700 dark:bg-amber-500/10 dark:text-amber-300",
    excited: "bg-orange-100 text-orange-700 dark:bg-orange-500/10 dark:text-orange-300",
    sad: "bg-sky-100 text-sky-700 dark:bg-sky-500/10 dark:text-sky-300",
    whisper: "bg-indigo-100 text-indigo-700 dark:bg-indigo-500/10 dark:text-indigo-300",
    angry: "bg-red-100 text-red-700 dark:bg-red-500/10 dark:text-red-300",
    neutral: "bg-gray-100 text-gray-600 dark:bg-white/10 dark:text-gray-300"
  };
  const PLAY_EVENT = "voicesample:play";
  const fmtTime = s => {
    if (!s || !isFinite(s)) return "0:00";
    const m = Math.floor(s / 60);
    const sec = Math.floor(s % 60).toString().padStart(2, "0");
    return m + ":" + sec;
  };
  const audioRef = React.useRef(null);
  const idRef = React.useRef(null);
  if (idRef.current === null) idRef.current = Math.random();
  const [playing, setPlaying] = React.useState(false);
  const [cur, setCur] = React.useState(0);
  const [dur, setDur] = React.useState(0);
  const [copied, setCopied] = React.useState(false);
  React.useEffect(() => {
    const onOther = e => {
      if (e.detail !== idRef.current && audioRef.current) {
        audioRef.current.pause();
        setPlaying(false);
      }
    };
    window.addEventListener(PLAY_EVENT, onOther);
    return () => window.removeEventListener(PLAY_EVENT, onOther);
  }, []);
  const toggle = () => {
    const a = audioRef.current;
    if (!a) return;
    if (playing) {
      a.pause();
      setPlaying(false);
    } else {
      window.dispatchEvent(new CustomEvent(PLAY_EVENT, {
        detail: idRef.current
      }));
      a.play();
      setPlaying(true);
    }
  };
  const copyValue = description ? "description: " + description + "\ntext: " + text : text;
  const copy = () => {
    if (navigator.clipboard) navigator.clipboard.writeText(copyValue);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };
  const seekTo = (clientX, el) => {
    const a = audioRef.current;
    if (!a || !dur) return;
    const rect = el.getBoundingClientRect();
    const ratio = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
    a.currentTime = ratio * dur;
    setCur(a.currentTime);
  };
  const pct = dur ? cur / dur * 100 : 0;
  const pill = label ? TONE_PILL.neutral : TONE_PILL[tone] || TONE_PILL.neutral;
  const pillLabel = label || "[" + (tone || "neutral") + "]";
  const lbl = "text-gray-400 dark:text-gray-500";
  return <div className="not-prose my-3 flex flex-col gap-3 rounded-2xl border border-gray-200 bg-white p-4 dark:border-white/10 dark:bg-white/[0.03]">
      <div className="flex items-start justify-between gap-3">
        <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
          <span className={"rounded-md px-2 py-0.5 font-mono text-xs font-semibold " + pill}>
            {pillLabel}
          </span>
          {note && <span className="text-xs text-gray-500 dark:text-gray-400">{note}</span>}
        </div>
        <button type="button" onClick={copy} aria-label={copied ? "Copied" : "Copy prompt"} className="flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs text-gray-500 transition hover:bg-gray-100 hover:text-gray-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:bg-white/10 dark:hover:text-gray-200">
          {copied ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <path d="M20 6 9 17l-5-5" />
            </svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <rect x="9" y="9" width="13" height="13" rx="2" />
              <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
            </svg>}
          {copied ? "copied" : "copy"}
        </button>
      </div>

      <div className="overflow-hidden rounded-lg bg-gray-50 px-3 py-2.5 font-mono text-xs leading-relaxed break-words whitespace-pre-wrap text-gray-700 dark:bg-white/5 dark:text-gray-300">
        {description ? <>
            <span className={lbl}>description:</span> {description}
            {"\n"}
            <span className={lbl}>text:</span> {text}
          </> : text}
      </div>

      <audio ref={audioRef} src={src} preload="metadata" onLoadedMetadata={e => setDur(e.currentTarget.duration)} onTimeUpdate={e => setCur(e.currentTarget.currentTime)} onEnded={() => {
    setPlaying(false);
    setCur(0);
    if (audioRef.current) audioRef.current.currentTime = 0;
  }} />

      <div className="flex items-center gap-3">
        <button type="button" onClick={toggle} aria-label={playing ? "Pause" : "Play " + (label || tone || "voice") + " sample"} className="flex size-9 shrink-0 items-center justify-center rounded-full bg-gray-900 text-white transition hover:bg-gray-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-900 focus-visible:ring-offset-2 dark:bg-white dark:text-gray-900 dark:focus-visible:ring-white dark:focus-visible:ring-offset-gray-900">
          {playing ? <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
              <rect x="6" y="5" width="4" height="14" rx="1" />
              <rect x="14" y="5" width="4" height="14" rx="1" />
            </svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
              <path d="M8 5v14l11-7z" />
            </svg>}
        </button>

        <div role="slider" aria-label="Seek" aria-valuemin={0} aria-valuemax={Math.round(dur) || 0} aria-valuenow={Math.round(cur)} tabIndex={0} onClick={e => seekTo(e.clientX, e.currentTarget)} onKeyDown={e => {
    const a = audioRef.current;
    if (!a || !dur) return;
    if (e.key === "ArrowRight") {
      a.currentTime = Math.min(dur, a.currentTime + 2);
      setCur(a.currentTime);
    } else if (e.key === "ArrowLeft") {
      a.currentTime = Math.max(0, a.currentTime - 2);
      setCur(a.currentTime);
    }
  }} className="relative h-1.5 flex-1 cursor-pointer rounded-full bg-gray-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 dark:bg-white/15">
          <div className="absolute inset-y-0 left-0 rounded-full bg-gray-900 dark:bg-white" style={{
    width: pct + "%"
  }} />
        </div>

        <span className="shrink-0 font-mono text-xs tabular-nums text-gray-500 dark:text-gray-400">
          {fmtTime(cur)} / {fmtTime(dur)}
        </span>
      </div>
    </div>;
};

every muga prompt is three parts: a `[tone]`, an optional `<event>`, and your
words. hear one first:

<VoiceSample tone="happy" note="a happy line" text="[happy] <laugh> Yaar tumne phir wahi joke maara!" src="/audio/muga/hero.mp3" />

## anatomy of a prompt

```
[happy]   <laugh>   Yaar tumne phir wahi joke maara!
   │         │                    │
 tone      event              your words
(the mood) (the sound)     (romanised hinglish)
```

every prompt is these three parts.

## the 3 rules that prevent most problems

1. **start every paragraph with one `[tone]`.** it must be the first token. no
   tone means flat delivery. one tone per paragraph; a blank line starts a new one.
2. **romanised hinglish only.** latin script. devanagari was never in training, so
   it comes out as garbage.
3. **match the event to the tone.** laughs belong to high, positive tones; sighs to
   low, reflective ones. a `<laugh>` in a `[sad]` line fights the model (matrix below).

everything else is detail.

<Note>
  **saying numbers, IDs and dates.** silk normalizes your `text` before speaking it, so
  amounts, dates, times and percentages are read out for you. anything that must be read
  digit by digit, like an OTP or an order number, has to be wrapped in double quotes. see
  [numbers, IDs & dates](/normalization).
</Note>

## tones

six moods. press play on any one, and copy the prompt to try it yourself.

<VoiceSample tone="neutral" note="facts, confirmations" text="[neutral] Aapka order place ho gaya hai. Confirmation SMS bhej diya gaya hai." src="/audio/muga/neutral.mp3" />

<VoiceSample tone="happy" note="light, casual chat" text="[happy] <chuckle> Arre yaar, kitne din baad baat hui! Sab badhiya chal raha hai?" src="/audio/muga/happy.mp3" />

<VoiceSample tone="excited" note="wins, surprises, hype" text="[excited] <laugh> Bhai sun, abhi abhi pata chala, wo job mil gayi mujhe!" src="/audio/muga/excited.mp3" />

<VoiceSample tone="sad" note="loss, disappointment" text="[sad] <sigh> Yaar, samajh sakti hoon. Itna kuch hua hai, time lagega." src="/audio/muga/sad.mp3" />

<VoiceSample tone="angry" note="frustration, blame" text="[angry] Tumne phir wahi kiya. Maine kitni baar bola tha aisa mat karo." src="/audio/muga/angry.mp3" />

<VoiceSample tone="whisper" note="secrets, late-night" text="[whisper] Phir achanak, kuch khatka hua. Maine darwaza dekha, koi nahi tha." src="/audio/muga/whisper.mp3" />

no tag means the default tone (`[neutral]` if nothing is set). the tone covers the
whole paragraph.

## inline events

drop these in the text, where you want the sound:

| event       | length   | sound                         |
| ----------- | -------- | ----------------------------- |
| `<laugh>`   | 0.5-1.5s | loud, voiced laughter         |
| `<chuckle>` | 0.3-0.7s | soft, amused, almost a breath |
| `<sigh>`    | 0.4-0.8s | audible exhale, breathy       |

rules:

* lowercase, angle brackets, no inner spaces: `<laugh>`, never `<Laugh>` or
  `< laugh >`. get it wrong and it's spoken as a word.
* one space on each side. never mid-word.
* position matters: `<laugh> kya baat hai` lands differently from
  `kya baat hai <laugh>`.
* stack at most two (`<laugh> <laugh>`) for a harder laugh. three or more gets unstable.

## tone × event compatibility

the rule that trips people up most. **laughs ride high tones; sighs ride low ones.**

<ToneMatrix />

mix contradictory pairs (a laugh in grief, a sigh in a hype shout) and the model
has almost no training to fall back on, so it fights itself.

## length and chunking

muga is built for **2 to 40 second** utterances.

* **2 to 30s**: the sweet spot. one to three sentences.
* **30 to 40s**: fine for a short monologue.
* **40s+**: split it. past 40s, tone drifts and you get repeats or cutoffs.

to chunk: break at sentence boundaries, keep each piece under 30s, re-state the
tone on each piece, and send them as separate calls.

## recipes

| you want                | prompt                                                                             |
| ----------------------- | ---------------------------------------------------------------------------------- |
| reassuring confirmation | `[neutral] Aapka order place ho gaya hai. Confirmation SMS bhej diya hai.`         |
| hype reaction           | `[excited] <laugh> Bhai jeet gaye, vishwas nahi ho raha!`                          |
| warm banter             | `[happy] <chuckle> Arre yaar, kitne din baad baat hui! Sab badhiya chal raha hai?` |
| empathy / bad news      | `[sad] <sigh> Yaar, samajh sakti hoon. Time lagega.`                               |
| secret / late night     | `[whisper] Phir achanak kuch khatka hua. Maine darwaza dekha, koi nahi tha.`       |
| frustration             | `[angry] Tumne phir wahi kiya. Maine kitni baar bola tha.`                         |

## using muga in a voice agent

muga sets tone per paragraph, so it needs the **whole tagged utterance up front**.
it can't tag half a sentence.

1. buffer the tokens streaming out of your LLM until the turn is complete.
2. you now have one fully tagged utterance.
3. send it to the TTS endpoint and stream the audio back to the call.

never forward partial LLM output. a fragment like `[hap` or a half-placed `<lau`
is **spoken literally, not rejected**, so validate before production. need
token-by-token low latency instead? use [mulberry](/prompting-mulberry). for
transport, see [streaming](/streaming) and the [pipecat integration](/pipecat).

### system prompt for your agent's LLM

hand this to the LLM that writes muga's lines. tune the wording, not the tags.

```text theme={null}
You write text spoken by the Silk Muga 1 text-to-speech model.

- Output only the final tagged text, no markdown, notes, or metadata.
- Romanised Hinglish only (Latin script). Never Devanagari.
- Write for speech: short, natural, one idea per sentence.

Tone tags
- Start every paragraph with exactly one tone tag, as the first token:
  [happy], [excited], [sad], [angry], [neutral], [whisper].
- One tone per paragraph. A blank line starts a new paragraph and a new tone.

Inline events
- Optional: <laugh>, <chuckle>, <sigh>. Lowercase, a space on each side,
  at most one per paragraph, placed where the sound occurs.
- Match the tone: <laugh>/<chuckle> with [happy]/[excited];
  <sigh> with [sad]/[angry]/[neutral]/[whisper]. Never mix contradictory emotions.

- Keep each paragraph under ~40 seconds (1 to 3 sentences). Don't be verbose.
```

## pre-flight checklist

before you ship a prompt, six yes/no checks:

1. starts with exactly one `[tone]`?
2. latin script only, no devanagari?
3. every event lowercase, spaces around it, none mid-word?
4. event matches the tone (laugh = high, sigh = low)?
5. under \~40s (1 to 3 sentences)?
6. in an agent: full utterance buffered before sending?

## troubleshooting

| what you hear                | cause                                        | fix                                           |
| ---------------------------- | -------------------------------------------- | --------------------------------------------- |
| flat delivery, tone ignored  | no `[tone]` at the start, or placed mid-text | put one `[tone]` at the very start            |
| garbled or wrong words       | devanagari or non-hinglish input             | romanised hinglish only                       |
| a laugh or sigh sounds off   | event doesn't match the tone                 | use the compatibility matrix                  |
| an event is spoken as a word | wrong casing or spacing                      | lowercase, no inner spaces, a space each side |
| drifts, repeats, or cuts off | utterance over \~40s                         | split into ≤30s chunks                        |
| inconsistent run to run      | sampling settings                            | set `temperature` to 0.7                      |

## faq

<AccordionGroup>
  <Accordion title="which tone is used if I don't add a tag?">
    the selected default tone, or `[neutral]` if none is set.
  </Accordion>

  <Accordion title="can I change tone mid-message?">
    not inside a paragraph. start a new paragraph (a blank line) with a new `[tone]`.
  </Accordion>

  <Accordion title="why does my laugh or sigh sound off?">
    it doesn't match the tone. laughs need high, positive tones; sighs need low
    ones. see the matrix.
  </Accordion>

  <Accordion title="can muga speak hindi written in devanagari?">
    no. it saw zero devanagari in training. `मैं ठीक हूँ` produces garbage, romanise
    it: `main theek hoon`.
  </Accordion>

  <Accordion title="how long can one utterance be?">
    2 to 40 seconds. past \~40s, split it into chunks of 30s or less.
  </Accordion>
</AccordionGroup>
