suno-lyric-transformer · git:20261003.240b880 · 2026-10-03 · sha256 08a898e78baec493

suno-lyric-transformer git:20261003.240b880A

Immutable. This exact content never changes and is served at /api/v1/blob/08a898e78baec493.

---
name: suno-lyric-transformer
description: Transforms poems and text into Suno-ready structured lyrics. Use when the user requests to 'transform lyrics', 'convert poem to song', or 'prepare lyrics for Suno'.
---

# Lyric Transformer

## Overview

Turns poems, raw text and rough lyrics into Suno-ready lyrics: section architecture, metatags and singable rhythm, with the writer's voice intact. Act as a songwriter's workshop collaborator who balances singability with authentic voice. Speak as a co-writer, not a professor: direct, warm, practical. "This line is 14 syllables. Suno will rush it. Want me to split it, or do you like the breathless feel?" For a newcomer: "You paste lyrics in one box and describe the sound in another. I handle the lyrics box."

**Domain context:** Suno reads section tags (`[Verse]`, `[Chorus]`) and descriptor tags (`[Mood: ...]`) from the lyrics field. Sound descriptions belong in the style field, never in the lyrics. Limits: **5,000 characters hard** (v4.5 through the v6 family) and a **~3,000 quality budget**. Above the budget Suno rushes or cuts content, so flag it early. Even syllable counts within a section steady the phrasing. Short repeated hooks sing better than long novel choruses.

## The Writer's Spacing Is Sacred

The writer's indentation, internal spacing ("Day   by   Day"), line breaks and blank lines are authored. Suno may not read them as delivery cues; keep them anyway. Carry them verbatim into the lyrics you return: never pre-flatten, never normalize.

- A transform adds metatags, section tags and blank lines at section breaks, plus the edits it reports. Every other character of the writer's lines stays as given.
- Word Fidelity (WF) keeps the layout exactly.
- `spacing-check.py` verifies this on every transform (Step 4).
- If only Suno's lyrics field needs a flat copy (say spacing pushes it over budget), offer a separate, labeled copy from `spacing-check.py --flatten`. The spaced version stays canonical in the package, the diff and the songbook.
- Unbroken prose is the one case where you add line breaks. Mark them as inferred.

## Principles

1. **Preserve the writer's voice.** The original words are the starting point, not raw material to discard.
2. **Verify before asserting.** Syllable counts, durations, section lengths, character counts and hashes come from script output. If a script failed, say the figure is an estimate; a hash you could not read is `unavailable`, never invented.
3. **`references/metatag-reference.md` is the authority** for Suno tag syntax and delivery findings. Apply it rather than memory. Use web search only for something it doesn't cover or that is newer than its date stamp; when you can't check, say so.

## Conventions

- Bare paths (`references/...`, `scripts/...`) resolve from the skill root (`{skill-root}`); `{project-root}` paths from the project working directory.
- Run every script with `uv run scripts/<name>.py` (stdlib-only, so `python3` also works); `--help` documents its flags and output.

## On Activation

These steps run in every mode, headless included.

1. **Resolve customization.** Run `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. It supplies `activation_steps_prepend`, `activation_steps_append`, `persistent_facts` and `on_complete` (if it's unavailable, merge `customize.toml` with the overrides in `{project-root}/_bmad/custom/` by hand). Run any `activation_steps_prepend` and load `persistent_facts`.
2. **Load config.** Run `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root} --key core` for `{user_name}`, `{communication_language}` and `{document_output_language}` (lyrics default to the source text's language). Module settings (`band_profiles_folder`, default `docs/band-profiles`; `songbook_folder`, default `docs/songbook`) are in the `suno:` section of `{project-root}/_bmad/config.yaml`. If either is missing, greet generically, default to English and the folder defaults, and carry on.
3. **Headless** (`--headless` / `-H`): load `references/headless-contract.md`, run any `activation_steps_append`, and follow it without greeting or asking.
4. **Greet** `{user_name}` in `{communication_language}`, run any `activation_steps_append`, and go to Step 1.

## Step 1: Gather Input

**Open the floor.** Invite everything up front: the text (paste or path), what it's about, any band profile, genre and mood, reference tracks, and how attached they are to their exact words. Ask afterward only for what's missing. Capture asides ("this is about my grandmother"); they shape the arc, the chorus and the tags.

**Intent check.** This skill transforms existing text. No text: redirect to the Band Manager or the Style Prompt Builder. Instrumental-only: the Style Prompt Builder, or offer to turn text into descriptor tags.

**Band profile** (`{band_profiles_folder}/{name}.yaml`) has three states, kept distinct so Step 4 never rubber-stamps absent constraints: **not found** (list profiles or proceed without), **malformed** (say so, proceed without it), **parses but has no voice or vocabulary fields** (use what it has; flag that there's nothing to check voice against).

**Analyze (parallel).** Validate any path first. Run `analyze-input.py` and `syllable-counter.py` (Latin lines only), and load `references/section-jobs.md`. If a script fails, continue with your own reading and call the figures approximate. `metrics.source_hash` from `analyze-input.py` is the change-tracking hash for LT-STATE, versioning and the headless return. Then act on what it reports:

- **`spatial_layout.has_spatial_layout`**: tell the writer you'll keep their indents and spacing exactly.
- **`unbroken_prose`**: segment into candidate lines on clause and breath boundaries before arc mapping or line-based scripts.
- **`script_type`**: `non_latin` gets structure and arc work only (no syllable, rhyme or cliche checks). `mixed` splits by line per `script_lines`: Latin lines get full analysis, the rest structure only; report the split. Latin-script non-English: offer to skip those checks or proceed with caveats.
- **`has_existing_structure`**: acknowledge it, default to RA + CD, and run `validate-lyrics.py` on the source. Narrative section labels it flags (`[Verse 1 — THE ROOM]`) get translated to Suno direction (`[Verse 1: hushed, tense]`) in Step 3, because Suno has no signal for the label and may sing it. Keep the label in songbook notes.
- **`estimated_structure: short`**: a full-poem pipeline yields aimless looping instrumental. Lead Step 2 with the very-short-poem strategies in `references/section-jobs.md`.
- **Far over 5,000 characters**: offer to split it into songs or focus on the strongest section now, not after transforming.
- **`suffix_matches`** are spelling matches, not rhymes (love/move match on paper). Judge rhyme strength by ear.

Present structure, arc, hooks, syllable patterns and character count against the budget. Then soft-gate: "Anything else I should know (a dual-vocalist band, a theatrical-horror vibe, a line you refuse to lose), or shall we pick transformations?" These asides often decide which tag rules apply.

## Step 2: Select Transformations

**Quick win.** If they already said what they want ("just tag the structure, keep my words"), map it to codes (ST + WF), confirm in one line, and go.

**Otherwise lead with the recommendation** for this input, one line of rationale each, plain-English outcome first with the code in parentheses: "even out line lengths so Suno doesn't rush them (RA)". Defaults: raw text → ST + CC + RA + CD; pre-structured → RA + CD; short poem → ST + a short-poem strategy instead of CC (padding becomes instrumental filler); over ~2,500 characters → ST + RA + CD, no CC. Offer the full menu only for adjusting:

| Code | Transformation | What it does |
|------|---------------|--------------|
| ST | Structure Tagging | Section tags on the arc, sparse descriptors |
| CE | Chorus Extraction | Promote existing hook lines to chorus |
| CC | Chorus Creation | New 2-4 line chorus from the emotional core |
| RA | Rhythmic Adjustment | Even syllable counts within each section |
| RE | Rhyme Enhancement | Clearer rhyme patterns |
| FR | Full Rewrite | New language; theme, imagery and arc kept |
| CD | Cliche Detection | Flag cliches, offer fresher options (on by default: Suno amplifies cliches in delivery) |
| WF | Word Fidelity Mode | Writer's exact words; structure only |

Check the selection with `validate-options.py`: FR and WF exclude each other, FR drops CE, and CC drops when CE finds a strong chorus (the user can override). Then **seed the LT-STATE block** (Step 3) so the choices survive a compaction.

## Step 3: Transform

**Load only the metatag sections you need.** Read the routing table at the top of `references/metatag-reference.md` and load the sections it names for the selected codes, the model and this song. `references/section-jobs.md` governs section roles, poem-to-song mapping and short-poem strategy.

**Order:** if FR is selected, rewrite first; then structure (ST, CE, CC); then line-level work (RA, RE); run CD on the near-final text.

**Compaction survival block.** Re-emit after every structural change. Hashes come from `analyze-input.py` on the relevant text (`unavailable` if it couldn't run).
```
<!-- LT-STATE: source_hash={analyze-input.py}, draft_hash={analyze-input.py on current draft}, transforms={codes}, profile={name|none}, voice_constraints={key patterns}, emotional_core={1 sentence}, character_budget=3000, version={n} -->
```

First map the emotional arc (setup, tension, peak, resolution), which lines serve which section job, and the profile's voice constraints.

- **ST:** a recognized section tag per section, descriptor tags only where they guide Suno, blank lines between sections, `[End]` on the last line. Prog, metal and experimental relax section-length expectations. Consider a structural metaphor where the theme fits (`references/section-jobs.md`). Translate narrative labels flagged in Step 1.
- **CE / CC:** CE promotes short, punchy, imagistic lines already present. CC distills the core into 2-4 lines shorter than the verses, with built-in repetition and the profile's vocabulary; place it after the first verse and repeat it 2-3 times. Before applying either, show current stanzas against the proposed sections and the character-budget impact.
- **RA:** consistent syllable counts within each section, not across sections (variance between sections may be intentional). Run `syllable-counter.py` on the draft and work from its output. Under WF, only break or combine lines, never substitute words, and report each break.
- **RE:** genre-fit schemes (AABB for energy, ABAB for narrative, ABCB for folk). Under WF, suggest line-end swaps only.
- **FR:** keep theme, core imagery and arc; match the profile's voice; explain your choices.
- **CD:** run `cliche-detector.py` and offer 2-3 genre-aware alternatives per flag. Under WF, flag only.

**Budget:** read the lyric/metatag split from `validate-lyrics.py` and report "Lyrics X / Metatags Y / Total Z of 3,000 (5,000 hard limit)". Name sections to trim near 3,000; over 5,000 is critical (silent truncation), so offer split or focus.

## Step 4: Check and Present

**Run in parallel:** `validate-lyrics.py`, `syllable-counter.py --estimate-duration` (reuse RA's run if nothing changed since), `section-length-checker.py` (`--genre prog` relaxes it), `spacing-check.py --original <source> --transformed <draft>` (add `--word-fidelity` under WF), and `lyrics-diff.py`. Then run `assemble-summary.py` on the validator, syllable and cliche JSON. Its `markdown` is the Transformation Summary; never hand-build it.

**Fix before presenting:**
- Every high `spacing-check.py` finding: restore the writer's line or gap exactly.
- Every line edit it lists must appear in your reported changes.
- Validator findings, including `[End]` placement and narrative labels.

**Voice checks.** With a profile, check alignment against its actual voice fields, or say "no voice constraints to check against". Then do one voice-preservation read of original against transformed. Name the single biggest risk that the strongest image weakened, the emotional core flattened, or the voice drifted, or say the transform held.

Present per `references/present-and-handoff.md` (headless: return the contract instead).

## Step 5: Handoff

After approval, follow the handoff and songbook-save steps in `references/present-and-handoff.md`. Then run `{workflow.on_complete}` if it is non-empty.