Back to skills
SkillHub ClubAnalyze Data & AIFull StackBackendData / AI

ace-music

Generate AI music using ACE-Step 1.5 via ACE Music's free API. Use when the user asks to create, generate, or compose music, songs, beats, instrumentals, or audio tracks. Supports lyrics, style prompts, covers, and repainting. Free API, no cost.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,126
Hot score
99
Updated
March 20, 2026
Overall rating
C0.0
Composite score
0.0
Best-practice grade
A88.4

Install command

npx @skill-hub/cli install openclaw-skills-ace-music

Repository

openclaw/skills

Skill path: skills/fspecii/ace-music

Generate AI music using ACE-Step 1.5 via ACE Music's free API. Use when the user asks to create, generate, or compose music, songs, beats, instrumentals, or audio tracks. Supports lyrics, style prompts, covers, and repainting. Free API, no cost.

Open repository

Best for

Primary workflow: Analyze Data & AI.

Technical facets: Full Stack, Backend, Data / AI.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install ace-music into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding ace-music to shared team environments
  • Use ace-music for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: ace-music
description: Generate AI music using ACE-Step 1.5 via ACE Music's free API. Use when the user asks to create, generate, or compose music, songs, beats, instrumentals, or audio tracks. Supports lyrics, style prompts, covers, and repainting. Free API, no cost.
---

# ACE Music - AI Music Generation

Generate music via ACE Music's free hosted API (ACE-Step 1.5 model).

## Setup

**API Key** is stored in env `ACE_MUSIC_API_KEY`. If not set:
1. Open https://acemusic.ai/playground/api-key in the browser for the user
2. Ask them to sign up (free) and paste the API key
3. Store it: `export ACE_MUSIC_API_KEY=<key>` or add to TOOLS.md

## Quick Generation

Use `scripts/generate.sh` for one-shot generation:

```bash
# Simple prompt (AI decides everything)
scripts/generate.sh "upbeat pop song about summer" --duration 30 --output summer.mp3

# With lyrics
scripts/generate.sh "gentle acoustic ballad, female vocal" \
  --lyrics "[Verse 1]\nSunlight through the window\n\n[Chorus]\nWe are the dreamers" \
  --duration 60 --output ballad.mp3

# Instrumental only
scripts/generate.sh "lo-fi hip hop beats, chill, rainy day" --instrumental --duration 120 --output lofi.mp3

# Natural language (AI writes everything)
scripts/generate.sh "write me a jazz song about coffee" --sample-mode --output jazz.mp3

# Specific settings
scripts/generate.sh "rock anthem" --bpm 140 --key "E minor" --language en --seed 42 --output rock.mp3

# Multiple variations
scripts/generate.sh "electronic dance track" --batch 3 --output edm.mp3
```

Script outputs file path(s) to stdout. Send the file to the user.

## Advanced Usage (curl/direct API)

For covers, repainting, or audio input β€” see `references/api-docs.md` for full API spec.

Key task types:
- `text2music` (default) β€” generate from text/lyrics
- `cover` β€” cover an existing song (requires audio input)
- `repaint` β€” modify a section of existing audio

## Parameters Guide

| Want | Use |
|------|-----|
| Specific style | Describe in prompt: "jazz, saxophone solo, smoky bar" |
| Custom lyrics | `--lyrics "[Verse]...[Chorus]..."` |
| AI writes everything | `--sample-mode` |
| No vocals | `--instrumental` |
| Longer songs | `--duration 120` (seconds) |
| Specific tempo | `--bpm 120` |
| Specific key | `--key "C major"` |
| Multiple outputs | `--batch 3` |
| Reproducible | `--seed 42` |
| Non-English vocals | `--language ja` (zh, en, ja, ko, etc.) |

## Notes

- API is **free forever** (confirmed by ACE Music team)
- Base URL: `https://api.acemusic.ai`
- Audio returned as base64 MP3, decoded automatically by the script
- Duration: if omitted, AI decides based on content
- For best results, use tagged mode (prompt + lyrics separated)


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### scripts/generate.sh

```bash
#!/usr/bin/env bash
# ACE-Step Music Generation via API
# Usage: generate.sh <prompt> [options]
# Options: --lyrics "..." --duration 30 --language en --instrumental --output file.mp3
#          --bpm 120 --key "C major" --seed 42 --sample-mode --batch 2

set -euo pipefail

# Config
API_KEY="${ACE_MUSIC_API_KEY:-}"
BASE_URL="${ACE_MUSIC_BASE_URL:-https://api.acemusic.ai}"
OUTPUT="output_$(date +%s).mp3"

# Defaults
DURATION=""
LANGUAGE="en"
INSTRUMENTAL="null"
BPM=""
KEY_SCALE=""
SEED=""
SAMPLE_MODE="false"
BATCH_SIZE=1
LYRICS=""
PROMPT=""
FORMAT="mp3"

# Parse args
while [[ $# -gt 0 ]]; do
  case "$1" in
    --lyrics) LYRICS="$2"; shift 2 ;;
    --duration) DURATION="$2"; shift 2 ;;
    --language) LANGUAGE="$2"; shift 2 ;;
    --instrumental) INSTRUMENTAL="true"; shift ;;
    --output|-o) OUTPUT="$2"; shift 2 ;;
    --bpm) BPM="$2"; shift 2 ;;
    --key) KEY_SCALE="$2"; shift 2 ;;
    --seed) SEED="$2"; shift 2 ;;
    --sample-mode) SAMPLE_MODE="true"; shift ;;
    --batch) BATCH_SIZE="$2"; shift 2 ;;
    --format) FORMAT="$2"; shift 2 ;;
    *) PROMPT="$1"; shift ;;
  esac
done

if [[ -z "$API_KEY" ]]; then
  echo "ERROR: ACE_MUSIC_API_KEY not set." >&2
  echo "Get your free API key at: https://acemusic.ai/playground/api-key" >&2
  exit 1
fi

if [[ -z "$PROMPT" && "$SAMPLE_MODE" == "false" ]]; then
  echo "Usage: generate.sh <prompt> [--lyrics '...'] [--duration 30] [--language en] [--instrumental] [--output file.mp3]" >&2
  exit 1
fi

# Build audio_config
AUDIO_CONFIG="{\"vocal_language\":\"$LANGUAGE\",\"format\":\"$FORMAT\""
[[ -n "$DURATION" ]] && AUDIO_CONFIG="$AUDIO_CONFIG,\"duration\":$DURATION"
[[ -n "$BPM" ]] && AUDIO_CONFIG="$AUDIO_CONFIG,\"bpm\":$BPM"
[[ "$INSTRUMENTAL" != "null" ]] && AUDIO_CONFIG="$AUDIO_CONFIG,\"instrumental\":$INSTRUMENTAL"
[[ -n "$KEY_SCALE" ]] && AUDIO_CONFIG="$AUDIO_CONFIG,\"key_scale\":\"$KEY_SCALE\""
AUDIO_CONFIG="$AUDIO_CONFIG}"

# Build message content
if [[ -n "$LYRICS" && -n "$PROMPT" ]]; then
  # Tagged mode
  CONTENT="<prompt>${PROMPT}</prompt>\n<lyrics>${LYRICS}</lyrics>"
elif [[ -n "$LYRICS" ]]; then
  CONTENT="$LYRICS"
else
  CONTENT="$PROMPT"
fi

# Escape for JSON
CONTENT_ESCAPED=$(echo -n "$CONTENT" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" | sed 's/^"//;s/"$//')

# Build request body
BODY="{\"messages\":[{\"role\":\"user\",\"content\":\"$CONTENT_ESCAPED\"}],\"audio_config\":$AUDIO_CONFIG,\"stream\":false"
[[ -n "$LYRICS" && -n "$PROMPT" ]] || true  # tagged mode handled via content
[[ "$SAMPLE_MODE" == "true" ]] && BODY="$BODY,\"sample_mode\":true"
[[ -n "$SEED" ]] && BODY="$BODY,\"seed\":$SEED"
[[ "$BATCH_SIZE" -gt 1 ]] && BODY="$BODY,\"batch_size\":$BATCH_SIZE"
BODY="$BODY}"

echo "🎡 Generating music..." >&2
echo "   Prompt: ${PROMPT:-[lyrics/sample mode]}" >&2
[[ -n "$DURATION" ]] && echo "   Duration: ${DURATION}s" >&2
echo "   Language: $LANGUAGE" >&2

# API call
RESPONSE=$(curl -s -X POST "${BASE_URL}/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "$BODY")

# Check for errors
if echo "$RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); exit(0 if 'choices' in d else 1)" 2>/dev/null; then
  # Extract metadata
  METADATA=$(echo "$RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['choices'][0]['message'].get('content',''))" 2>/dev/null || echo "")
  
  # Extract and save audio(s)
  COUNT=$(echo "$RESPONSE" | python3 -c "
import sys,json
d=json.load(sys.stdin)
audios=d['choices'][0]['message'].get('audio',[])
print(len(audios))
" 2>/dev/null || echo "0")

  if [[ "$COUNT" -eq 0 ]]; then
    echo "ERROR: No audio in response" >&2
    echo "$RESPONSE" >&2
    exit 1
  fi

  echo "$RESPONSE" | python3 -c "
import sys, json, base64
d = json.load(sys.stdin)
audios = d['choices'][0]['message'].get('audio', [])
output = '$OUTPUT'
for i, a in enumerate(audios):
    url = a['audio_url']['url']
    b64 = url.split(',', 1)[1]
    fname = output if len(audios) == 1 else output.rsplit('.', 1)[0] + f'_{i+1}.' + output.rsplit('.', 1)[1]
    with open(fname, 'wb') as f:
        f.write(base64.b64decode(b64))
    print(f'Saved: {fname}', file=sys.stderr)
    print(fname)
"

  if [[ -n "$METADATA" ]]; then
    echo "" >&2
    echo "πŸ“‹ Metadata:" >&2
    echo "$METADATA" >&2
  fi
else
  echo "ERROR: API request failed" >&2
  echo "$RESPONSE" >&2
  exit 1
fi

```

### references/api-docs.md

```markdown
# ACE-Step OpenRouter API Reference

**Base URL:** `https://api.acemusic.ai`
**Auth:** `Authorization: Bearer <api-key>`
**Get API Key:** https://acemusic.ai/playground/api-key

## Generate Music

**POST** `/v1/chat/completions`

### Request Parameters

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `model` | string | No | auto | Model ID |
| `messages` | array | **Yes** | - | Chat message list |
| `stream` | boolean | No | false | Enable streaming |
| `audio_config` | object | No | null | Audio config (see below) |
| `temperature` | float | No | 0.85 | LM sampling temperature |
| `top_p` | float | No | 0.9 | Nucleus sampling |
| `seed` | int/string | No | null | Random seed |
| `lyrics` | string | No | "" | Lyrics (takes priority over messages) |
| `sample_mode` | boolean | No | false | LLM auto-generates prompt/lyrics |
| `thinking` | boolean | No | false | LLM thinking mode |
| `use_format` | boolean | No | false | Enhance prompt/lyrics via LLM |
| `use_cot_caption` | boolean | No | true | Rewrite music description via CoT |
| `use_cot_language` | boolean | No | true | Auto-detect language via CoT |
| `guidance_scale` | float | No | 7.0 | Classifier-free guidance |
| `batch_size` | int | No | 1 | Number of samples |
| `task_type` | string | No | "text2music" | Task: text2music, cover, repaint |
| `repainting_start` | float | No | 0.0 | Repaint start (seconds) |
| `repainting_end` | float | No | null | Repaint end (seconds) |
| `audio_cover_strength` | float | No | 1.0 | Cover strength (0.0-1.0) |

### audio_config Object

| Field | Type | Default | Description |
|---|---|---|---|
| `duration` | float | null | Duration in seconds |
| `bpm` | integer | null | Beats per minute |
| `vocal_language` | string | "en" | Language code (en, zh, ja, etc.) |
| `instrumental` | boolean | null | Instrumental only (no vocals) |
| `format` | string | "mp3" | Output format |
| `key_scale` | string | null | Musical key (e.g. "C major") |
| `time_signature` | string | null | Time signature (e.g. "4/4") |

## Input Modes

### Mode 1: Tagged (Recommended)
```json
{
  "messages": [{"role": "user", "content": "<prompt>A gentle acoustic ballad, female vocal</prompt>\n<lyrics>[Verse 1]\nSunlight through the window\n\n[Chorus]\nWe are the dreamers</lyrics>"}],
  "audio_config": {"duration": 30, "vocal_language": "en"}
}
```

### Mode 2: Natural Language (sample_mode)
```json
{
  "messages": [{"role": "user", "content": "Generate an upbeat pop song about summer"}],
  "sample_mode": true,
  "audio_config": {"vocal_language": "en"}
}
```

### Mode 3: Lyrics Only
```json
{
  "messages": [{"role": "user", "content": "[Verse 1]\nWalking down the street\n\n[Chorus]\nDance with me tonight"}],
  "audio_config": {"duration": 30}
}
```

### Mode 4: Separate lyrics + prompt
Use `lyrics` field for lyrics, `messages` text becomes the prompt.

## Audio Input (for covers/repainting)

Multimodal messages with base64 audio:
```json
{
  "messages": [{"role": "user", "content": [
    {"type": "text", "text": "Cover this song in jazz style"},
    {"type": "input_audio", "input_audio": {"data": "<base64>", "format": "mp3"}}
  ]}],
  "task_type": "cover"
}
```

## Response

Audio is returned as base64 data URL in `choices[0].message.audio[0].audio_url.url`:
- Format: `data:audio/mpeg;base64,<base64_data>`
- Metadata in `choices[0].message.content` (caption, BPM, duration, key, lyrics)

## List Models

**GET** `/v1/models` β€” returns available models

## Health Check

**GET** `/health` β€” returns `{"status": "ok"}`

```



---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### _meta.json

```json
{
  "owner": "fspecii",
  "slug": "ace-music",
  "displayName": "ACE Music - Free Suno Alternative Generate unlimited AI music for free using ACE-Step 1.5. Full songs with vocals, lyrics, any genre, any language. No subscription, no credits, no limits. The open-source Suno alternative, powered by ACE Music's free API.",
  "latest": {
    "version": "1.0.0",
    "publishedAt": 1771464200986,
    "commit": "https://github.com/openclaw/skills/commit/c0a510771e56fb26aa12cecc444ad3d6f5b963a1"
  },
  "history": []
}

```

ace-music | SkillHub