suno-style-prompt-builder · git:20260628.fda38fd · 2026-06-28 · sha256 ecf455b8f6b5fe97

suno-style-prompt-builder git:20260628.fda38fdA

Immutable. This exact content is served forever at /api/v1/blob/ecf455b8f6b5fe97.

---
name: suno-style-prompt-builder
description: Generates model-aware Suno style prompts. Use when user says 'build a style prompt', 'generate style prompt', or 'create a Suno prompt'.
---

# Style Prompt Builder

## Overview

This skill generates Suno-ready style prompts optimized for the user's chosen model tier, blending band profile baselines with per-song creative direction. Act as a producer's sound engineer who thinks in sonic textures, frequency ranges, and production approaches. Through guided conversation (or headless structured input), it produces a complete prompt package: style prompt, exclusion prompt, slider recommendations, and an optional experimental wild card variant.

**Domain context:** Suno's model families respond to fundamentally different prompt styles -- v4.5 wants conversational descriptions while v5 wants crisp, film-brief descriptors; never mix the two approaches. Style prompts are hard-capped at 1,000 characters (200 for v4 Pro) and silently truncated. Real-world testing suggests v4.5-all may only effectively use ~200 characters. Front-load all essential genre, mood, and vocal descriptors in the first ~200 characters (the "critical zone") -- everything after is supplementary. The "Exclude Styles" field is separate and follows its own rules.

**Design rationale (load-bearing constraints):**

- **Decompose, never name-drop.** Never put artist names in style prompts -- Suno will not reliably replicate them. Decompose references into concrete sonic descriptors. When you are not confident you know an artist's distinctive sound, web-search to verify *before* decomposing; never fabricate sonic details. A wrong decomposition produces a prompt that sounds nothing like intent, and the user won't know why.
- **Frame positively.** Translate negatives ("no screaming") into positives ("raw melodic singing with grit on peaks"). Suno does not reliably process in-prompt negation; the Exclude Styles field carries the negatives.
- **Less exclusion is more.** Prioritize the 2-3 most important exclusions; too many destabilize the arrangement.
- **Always output the full package** (style + exclusion + sliders + wild card). Generating everything up front is cheaper than re-running per piece, and the wild card encourages creative exploration without risk.
- **Capture-don't-interrupt.** When users volunteer lyric ideas, structure preferences, or mix notes mid-build, acknowledge and store them for handoff to the appropriate sibling skill rather than redirecting.

## Conventions

- Bare paths (e.g. `references/model-prompt-strategies.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.

## Activation Mode Detection

**Check activation context immediately:**

1. **Headless mode**: If user passes `--headless` or `-H` flags, or intent clearly indicates non-interactive execution:
   - `--headless:from-profile` -- generate using only profile baseline
   - `--headless:custom` -- generate from provided parameters without profile
   - `--headless:refine` -- accept an existing prompt + structured adjustments and apply deltas. Accepts the sibling Feedback Elicitor's `adjustment_recommendations` shape so its output can be piped in directly:
     ```json
     {
       "prompt": "string", "model": "string",
       "style_prompt": {"add": [], "remove": [], "reorder_notes": ""},
       "exclusions": {"add": [], "remove": []},
       "sliders": {"weirdness": "", "style_influence": ""},
       "model_suggestion": ""
     }
     ```
     `reorder_notes` is free-text reordering guidance (the producer shape); apply it as a re-front-loading instruction. A legacy `adjustments.reorder: string[]` / `adjustments.replace[]` shape is still accepted for backward compatibility.
   - `--headless:migrate` -- accept existing prompt + original model + target model, reformat using target model's strategy from `references/model-prompt-strategies.md`
   - `--headless` with profile name -- hybrid mode (profile baseline + overrides)
   - Bare `--headless` with no sub-mode and no profile -- require at minimum `genre_mood`; apply defaults
   - Reload `references/model-prompt-strategies.md` before generating (see Compaction Survival), then output the complete prompt package as the success JSON below. No interaction; headless **skips the decomposition-confirmation step** and records that skip in `decisions[]`.
   - **Validate before emitting (all sub-modes, including `:refine` and `:migrate`):** run `uv run scripts/validate-prompt.py --style "{style_prompt}" --exclude "{exclusion_prompt}" --model "{target_model}"` on the reformatted/adjusted prompt -- the migrate/refine paths produce a new prompt against a (possibly new) model's char + critical-zone budget, so the same fail-fast check Step 5 runs interactively applies here. Fix anything flagged, re-run, and fold the script's report into the `validation` field of the success JSON (or note it if the script can't execute).
   - **Sliders obey the per-song anti-anchoring rule even headless:** choose Weirdness/Style Influence fresh from the Slider Guidelines table by reasoning from song type + what each slider does -- never default to a profile's stored `sliders:` (the bare-Demo fallback is the only exception). Log each chosen value with its behavioral reasoning in `decisions[]`. User-supplied slider values are authoritative -- pass them through, don't re-derive.

   **Headless defaults** (when optional parameters omitted): Creativity=Balanced, Model=v4.5-all, Wild card=disabled (unless `include_wild_card=true`)

   **Headless success contract**: On completion, emit the package as JSON. `decisions[]` logs every non-obvious call the user would have weighed in interactively -- dangerous-word substitutions, genre demotions, slider choices, the skipped decomposition confirmation -- each with a one-line `reason`:
   ```json
   {
     "status": "complete",
     "model": "v5 Pro",
     "style_prompt": "string",
     "exclusion_prompt": "string",
     "sliders": {"weirdness": 55, "style_influence": 75, "audio_influence": null},
     "wild_card": {"style_prompt": "string", "reasoning": "string"},
     "validation": { "...": "validate-prompt.py report (or note if unavailable)" },
     "decisions": [
       {"call": "substituted 'progressive heavy groove' for 'metal'", "reason": "profile excludes screaming; 'metal' triggers harsh vocals"},
       {"call": "skipped decomposition confirmation", "reason": "headless mode -- no interactive turn available"}
     ]
   }
   ```
   `wild_card` is `null` when disabled. `status` is `complete` or `blocked`.

   **Headless blocked/error contract**: When required inputs are missing, return `status: "blocked"` with the missing fields and a one-line reason; still include any `decisions[]` recorded so far:
   ```json
   {"status": "blocked", "missing": ["genre_mood"], "reason": "Required input 'genre_mood' not provided for --headless:custom mode.", "decisions": []}
   ```

2. **Interactive mode** (default): Proceed to On Activation

## On Activation

1. **Resolve customization** -- run `{project-root}/_bmad/scripts/resolve_customization.py {skill-name}` to merge `customize.toml` with any team/user overrides. Apply `activation_steps_prepend` before the steps below and `activation_steps_append` after greeting; load `persistent_facts` (durable project context). If the resolver is unavailable, proceed with defaults.
2. **Load config via bmad-init skill** -- use `{user_name}` for greeting, `{communication_language}` for all communications. Fallback: greet generically, default to English. Do not block on missing config.
3. **Greet user** and proceed to Step 1

## Compaction Survival (HARD RULE)

All load-bearing safety knowledge -- scream/harsh-vocal triggers, the Dangerous Words / keyboard-pull list, the Genre Term Behavior Table, and the **Slider Guidelines table + per-song anti-anchoring rule** (choose Weirdness/Style Influence fresh each song reasoning from what each slider DOES; never anchor to a profile's stored `sliders:` defaults or to "what similar catalog songs used" -- a profile's stored sliders are a weak fallback for a bare Demo *only*, the single exception) -- lives in `references/model-prompt-strategies.md`. A long interactive session or an open-ended Step 5 refine loop can compact that reference out of context, and a prompt built without it can silently ship "metal", "cinematic", an unpaired heavy genre that triggers screaming or pulls keyboards, or a slider value lazily anchored to a profile default instead of chosen for the song.

**Therefore: before EVERY build and EVERY refine generation, (re)load `references/model-prompt-strategies.md` and treat its gotcha tables as non-negotiable inputs.** Do not generate or revise a style prompt from memory of these tables -- reload them. `validate-prompt.py` is the deterministic backstop (it flags enumerable triggers), but the substitution decision and any term not in its table still require the live reference.

## Workflow Steps

### Step 1: Gather Inputs

**Open the floor first.** Invite the user to share everything they have in one go -- genre, mood, vibe, "sounds like X meets Y", a band profile name, reference tracks, target model, exclusions, paths to anything relevant. The dump replaces most of the question script; then ask only for what's still missing. Adapt the invitation to the input: a vague "build me a prompt" gets "tell me what you're going for"; a profile name or reference already in hand gets "what do you want this song to do differently from the baseline?".

**Signpost build vs. refine at the front door.** If the user's intent is to *adjust output they already generated and listened to* ("the vocals came out too harsh", "make it less busy", "this generation drifted"), that is post-generation feedback -- hand it toward the **Feedback Elicitor** rather than building a fresh prompt here. This skill builds and migrates prompts; the Elicitor maps listening feedback into adjustments. A new build from a fresh creative direction stays here.

**Standalone (no agent/Mac orchestration):** When this skill is invoked directly rather than through the Band Manager agent, the in-skill `:refine` and `:migrate` machinery is still available to the user -- they don't need the Feedback Elicitor or the agent to refine or model-migrate an existing prompt. If a standalone user hands you an existing prompt plus listening feedback, do the refine here (apply deltas, re-front-load, re-validate via Step 5 / the headless validate clause); if they hand you a prompt + a target model, do the migrate here (reformat to the target model's strategy, re-validate against its char budget). Only route to the Feedback Elicitor when it's actually present in the user's setup.

**Expert quick-win short-circuit.** If the opening dump already yields model + musical direction + creativity intent (an experienced user who handed you everything), skip the rest of the gather and proceed straight to Step 2 -- confirm only genuine ambiguities. Don't re-ask for things already provided. **If the user supplied explicit slider values, treat them as authoritative** -- pass them through to Step 3 and do not re-derive them from the table or a profile default.

**Required:** At least one source of musical direction -- genre, mood, vibe, "sounds like X meets Y", or modifications to a loaded band profile baseline.

**Optional but valuable:**
- **Band profile** -- read from `docs/band-profiles/{profile-name}.yaml`. Use `reference_tracks` if present. If not found, list available profiles. If fields are missing, warn and fill from conversation.
- **Model** -- default to profile's `model_preference` if available. Options: v4.5-all (free), v4 Pro (200-char limit), v4.5 Pro, v4.5+ Pro, v5 Pro, v5.5 Pro.
- **Creativity mode** -- Conservative (genre-pure, Weirdness 20-35), Balanced (default, 40-60), Experimental (unexpected fusions, 65-85)
- **Specific requests** -- instrument preferences, mood descriptions, exclusions
- **Reference tracks** -- decompose into concrete style descriptors (see `references/model-prompt-strategies.md` for confidence check and decomposition framework)
- **Inspo playlists (v4.5+ Pro)** -- suggest as alternative to manual reference decomposition when user has successful generations or real reference tracks

**No profile loaded:** Need genre, mood, and vocal direction at minimum. Offer to proceed without profile or hand off to Profile Manager.

**Instrumental detection:** If the profile sets `instrumental: true` (or the user asks for an instrumental / no-vocals track), flag it now and carry it into Steps 2-3 -- vocal direction is not a required input for instrumental songs, and the build branches accordingly (see Step 2's instrumental branch).

**Tier detection:** Determine from profile `tier` field or ask. Affects slider and Exclude Styles field availability (Weirdness/Style Influence are Pro/Premier only).

**Efficiency:** When model is known during Step 1, load `references/model-prompt-strategies.md` alongside the profile read.

### Step 2: Build Style & Exclusion Prompts

(Re)load `references/model-prompt-strategies.md` for model-specific construction rules, genre term behavior, and dangerous word lists -- per the Compaction Survival rule, this reload happens before every build, not just the first.

**Instrumental branch (when instrumental was flagged in Step 1):** Drop all vocal direction from the style prompt and skip the Vocal-Gender recommendation in Step 3 -- there are no vocals to describe. Skip the scream-trigger *pairing* prompts too: an unpaired heavy genre term (`metal`, `sludge`) needs no positive vocal instruction here because there are no vocals to protect (the validator's `trigger` finding for an unpaired heavy term is a non-issue for instrumentals -- note it as handled rather than "fixing" it with a vocal phrase). Note `[Instrumental]` handling for the package. **Redirect the critical-zone budget that vocals would have used into arrangement, texture, and dynamics** -- lead instrument character, interplay, build/decay arc, production space -- since those now carry the song's identity.

**Strategy:** From profile baseline, from scratch, or hybrid (default when profile exists).

**Key limitation:** The style prompt sets ONE overall sonic mood. Suno does NOT actually shift tempo within a song — "tempo change" or "tempo shift" prompts produce arrangement-density variation (instrumentation pullback / compression), not actual BPM movement. Set baseline feel here; use lyric density and rhythm-noun metatags (`[Heavy: halftime]`, `[Double Time]`) for section-level perceived-tempo changes.

**Outcome:** A model-formatted style prompt that front-loads genre/mood/vocals in the critical zone, uses genre-safe terminology, and respects character limits. The prompt should:

- Follow the model's formatting style (v4.5: conversational sentences; v5/v5.5: crisp 5-8 descriptor film-brief; v4 Pro: simple descriptors within 200 chars)
- Translate reference tracks into concrete descriptors (show decomposition to user for confirmation before building)
- Apply the selected creativity mode
- Use genre-safe word choices per the Genre Term Behavior Table and Dangerous Words list in the strategies reference

**Genre word triggers** -- words that override other instructions:
- **"Metal"** triggers screaming/harsh vocals. For heavy without screaming: "progressive heavy groove", "heavy groove"
- **"Sludge"** triggers harsh vocals. Use "heavy", "thick", "dense"
- **"Death"**, **"thrash"**, **"black"** (as genre modifiers) trigger extreme vocal styles
- When a profile specifies these genres but excludes screaming, automatically substitute safe alternatives

**Keyboard-pull dangerous words** -- **"baroque"**, **"orchestral"**, **"cinematic"**, and **"rock opera"** pull theatrical/keyboard/synth-heavy or cinematic-light arrangements when guitars/bass should lead. These are texture modifiers, not genres. Replace per the Dangerous Words and Keyboard Triggers table in the strategies reference (e.g. "rock opera" -> "power ballad, dynamic shifts, building from gentle to crushing"). `validate-prompt.py` flags them; the reference carries the per-word rewrite.

**Rhythm nouns over tempo adjectives:** "halftime", "double-time", "four-on-the-floor", "shuffle", "breakbeat" lock feel more effectively than "slow", "fast", "upbeat"

**Instrument bleed-through:** The style prompt sets a GLOBAL instrument palette; instruments bleed into ALL sections regardless of section-level tags. Warn users requiring section-specific instrumentation. See strategies reference for mitigation (accents suffix, end-placement, stems workflow).

**Exclusion prompt** (Exclude Styles content):

- **Pro/Premier:** Output as comma-separated list for Suno's dedicated Exclude Styles field. With exclusions handled separately, heavier genre language is safe in the style prompt.
- **Free tier:** No Exclude Styles field. Translate exclusion intentions into positive style prompt language.
- Sources: profile `exclusion_defaults`, user "no X" requests, genre-inferred exclusions
- Rules: keep concise (under ~200 characters for the exclusion field), be specific, prioritize 2-3 most important, add positive reinforcement alongside negatives
- **Belt-and-suspenders:** Translate negative phrases to positive style prompt language AND put originals in Exclude Styles

### Step 3: Slider & Parameter Recommendations

**Pro/Premier sliders -- choose fresh per song (anti-anchoring rule):** Pull Weirdness and Style Influence from the **Slider Guidelines table** in `references/model-prompt-strategies.md` (reloaded per Compaction Survival) by reasoning from the song's type + counter-genre needs + what each slider actually DOES -- Weirdness adds unpredictability/non-obvious choices, Style Influence governs how tightly Suno follows the prompt. **The sliders are the deliberate per-song differentiator.** Do NOT anchor to a band profile's stored `sliders:` defaults, nor nudge up/down from "what similar catalog songs used" -- that is the documented failure mode (recommending 55 by anchoring "above the 45 default" for a song that wanted ~75). **The one exception:** a bare Demo ("just make me something") may fall back to the profile's stored `sliders:` if present. Audio Influence is the slider commonly left at a standard value (~25% for Personas; see the Voices table for Voice cases). Log the chosen values + the behavioral reasoning (headless: in `decisions[]`).

**Free tier:** Note sliders unavailable. Recommend Vocal Gender selection and Lyrics Mode.

**Instrumental songs:** Skip the Vocal-Gender recommendation entirely and set Lyrics Mode to Instrumental -- there is no vocal to gender.

**Additional parameters (all tiers):**
- Lyrics Mode (Manual/Auto), Song title suggestion
- Persona reference from profile if available (Pro/Premier). When Persona active: keep additional style simple (1-2 genres, 1 mood, 2-4 instruments), Persona auto-populates Style of Music field -- build on it, don't replace
- Persona sourcing: use clear, stable lead vocals; dual Personas unreliable
- v5.5 Voices: drop gender descriptors (Voice defines them), start Audio Influence at 55-70%
- v5.5 Custom Models: drop generic production descriptors the model already knows

**Exclude Styles output:** Always comma-separated list for direct copy-paste: `screaming vocals, steel guitar, autotune, heavy distortion`

### Step 4: Wild Card Variant

Generate an experimental alternative that pushes creative boundaries.

**Twist dial** -- offer before generating: (a) genre fusion, (b) era/production shift, (c) mood inversion, (d) instrumentation flip, (e) surprise me. Default to (e).

Rules: twist one or two major elements along the chosen direction, keep it musically coherent, generate a complete style prompt, label clearly as experimental.

**Skip when:** user explicitly asked for conservative only, or headless mode (unless `include_wild_card=true`).

### Step 5: Validate & Present

**Validate first (fail-fast).** Run `uv run scripts/validate-prompt.py --style "{style_prompt}" --exclude "{exclusion_prompt}" --model "{model_name}"` on the generated prompts and read the JSON back. The script deterministically handles char/critical-zone budgets, section-tag contamination, asterisks, genre front-loading, and enumerable dangerous-word / scream-trigger / `!` detection (the `trigger` category). Fix anything it flags, then re-run. If the script cannot execute (no Python/uv), perform the equivalent checks by hand from its `--help` and the strategies reference.

**Then self-review only what the script cannot judge** (with the strategies reference reloaded): genre-term *appropriateness* for the intended sound (the script flags a flagged term but cannot decide the right substitution), dangerous-word *semantics* in context, reference-decomposition fidelity, and alignment with the user's stated intent. Do not re-scan for things the validator already computed -- that is the validator's job. Fix silently.

**Present** with version numbers (v1, v2, v3...) and a one-line formatting rationale:

```
## Style Prompt v{N} ({model_name}) -- {formatting_rationale}
{character_count}/{limit} characters

{style_prompt}

## Exclude Styles
{character_count}/~200 characters (target for Exclude Styles field)

{exclusion_prompt}

## Parameter Recommendations
- Weirdness: {value} -- {reasoning}
- Style Influence: {value} -- {reasoning}
- Vocal Gender: {value}
{persona_note_if_applicable}

## Wild Card Variant
{wild_card_prompt}
{wild_card_reasoning}
```

**Copy-ready output** after the formatted presentation:

```
### Copy-Ready: Style Prompt (paste into Suno's "Style of Music" field)
{style_prompt}

### Copy-Ready: Exclude Styles (paste into Suno's "Exclude Styles" field -- Pro/Premier only)
{exclusion_prompt}
```

**Refinement:** Invite adjustments. **Before each refine generation, reload `references/model-prompt-strategies.md`** (Compaction Survival rule) -- a long refine loop is exactly where the safety tables get compacted away. Only regenerate affected outputs (creativity change = style + wild card; model change = style formatting; exclusion change = exclusion only). Re-run `validate-prompt.py` on anything regenerated. When switching models mid-refinement, preview impact first.

**Multi-model:** If user has no model preference, generate both v4.5-conversational and v5-film-brief variants.

**Iteration guidance:** Generate 3-5 versions on Suno before modifying the prompt. Change only 1-2 variables per iteration. For v5 Pro, Suno Studio's section editing, stems, and alternates can address issues without re-prompting. At session end, offer collected summary of all versions with deltas.

**Version ledger (compaction-proof).** A multi-version refine loop is exactly long enough to compact away the version history before you can offer the end-of-session summary. As each version is presented, append a one-line entry -- `vN | {one-line prompt or its key change} | {changed variable}` -- to a `.style-prompt-ledger.md` scratch file in the working directory (create on v1). The end-of-session summary reads from this ledger, so it survives compaction regardless of how long the refine loop ran. This is a lightweight scratch log, not a Decision-Log Workspace -- one appended line per version, nothing more.

**Pro tier tip:** Legacy Editor can replace/regenerate individual sections, rearrange via drag-and-drop, and preview alternatives. Recommend for dramatic section contrasts.

**Scope note:** Cover/remix prompt building not supported. Use Suno's built-in Cover feature (see strategies reference).

**Complete** when user accepts prompt package, ends session, or hands off to another skill.

## Scripts

**Invoke via `uv run scripts/<name>.py`** — uv reads the PEP 723 inline metadata and provisions any dependencies automatically. `validate-prompt.py` is dependency-free (stdlib only), so if `uv` is unavailable you can install it (`pip install uv`) or run it directly with `python3`.

`validate-prompt.py` -- Deterministically validates a prompt package: style prompt character count (v4 Pro=200, v4.5+/v5=1,000), critical zone, section-tag/asterisk contamination, genre front-loading, exclusion length/count, and enumerable dangerous-word / scream-trigger / `!` detection (`trigger` category, sourced from `_shared/suno_constants.py`). Run `uv run scripts/validate-prompt.py --style "..." --exclude "..." --model "{model_name}"`. The script flags triggers; the LLM still decides the substitution. Run `--help` for details.