Skip to content

Commit 42d22dd

Browse files
harajlimclaude
andcommitted
Initial commit: /vibe-sing skill
A Claude Code skill that ends a session with a song. Reads the current session transcript via CLAUDE_CODE_SESSION_ID, asks Gemini for a user-centric music prompt (no corny tech references), calls Google Lyria to compose with vocals, and auto-plays via afplay. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 parents  commit 42d22dd

8 files changed

Lines changed: 414 additions & 0 deletions

File tree

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
GOOGLE_API_KEY=your-google-ai-studio-key-here
2+
# Optional: override the Gemini model (defaults to gemini-3-flash-preview)
3+
# VIBE_SING_GEMINI_MODEL=gemini-3-pro-preview

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.env
2+
.venv
3+
generations/
4+
__pycache__/
5+
*.pyc
6+
.DS_Store

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 MH (@harajlim)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# /vibe-sing
2+
3+
A Claude Code skill that ends your session with a song.
4+
5+
Pipeline: **Claude Code session transcript → Gemini (mood translation) → Google Lyria 3 (music) → auto-play.**
6+
7+
- `/vibe-sing` — 30-second clip (default)
8+
- `/vibe-sing pro`~2-minute full song
9+
10+
## Why it isn't corny
11+
12+
Both the transcript filter and the Gemini system prompt explicitly forbid references to programming, files, libraries, bugs, or anything technical. The output is a *cinematic mood prompt* — genre, instrumentation, tempo, feel — not a song about your session. A listener should never guess what you were working on.
13+
14+
## Install
15+
16+
Clone directly into Claude Code's skills directory:
17+
18+
```bash
19+
git clone https://github.com/harajlim/vibe-sing.git ~/.claude/skills/vibe-sing
20+
cd ~/.claude/skills/vibe-sing
21+
22+
# Python deps
23+
python3 -m venv .venv
24+
.venv/bin/pip install -r requirements.txt
25+
26+
# API key — get one at https://aistudio.google.com/apikey
27+
cp .env.example .env
28+
$EDITOR .env # paste your GOOGLE_API_KEY
29+
```
30+
31+
Then in any Claude Code session, type `/vibe-sing`.
32+
33+
> **Hacking on the source?** Clone anywhere and symlink instead:
34+
> `ln -s "$(pwd)" ~/.claude/skills/vibe-sing` — edits go live immediately.
35+
36+
## Configuration
37+
38+
Env vars (set in `.env` or shell):
39+
40+
- `GOOGLE_API_KEY` — required.
41+
- `VIBE_SING_GEMINI_MODEL` — defaults to `gemini-flash-latest` (auto-tracks newest Flash). Pin a version like `gemini-2.5-flash` if you want.
42+
43+
Output mp3s land in `./generations/` (gitignored).
44+
45+
## How it works
46+
47+
1. Finds the JSONL transcript of the current session at `~/.claude/projects/<encoded-cwd>/<session>.jsonl` (picks the most recently modified — i.e. the live session).
48+
2. Extracts user prompts and assistant prose. Skips tool calls, tool results, thinking blocks, and system reminders. Up to ~100k tokens, tail-biased.
49+
3. Sends to Gemini with strict instructions: cinematic mood prompt only, no technical references, no specifics, no corniness.
50+
4. Sends Gemini's prompt to Lyria 3 (clip or pro).
51+
5. Saves the mp3 and `open`s it (macOS default audio player).
52+
53+
## Files
54+
55+
```
56+
vibe-sing/
57+
├── SKILL.md # instructions Claude follows when /vibe-sing fires
58+
├── run.sh # launcher (picks .venv/bin/python or system python3)
59+
├── vibe_sing.py # pipeline
60+
├── requirements.txt # google-genai, python-dotenv
61+
├── .env.example # template for your GOOGLE_API_KEY
62+
└── generations/ # output mp3s (gitignored)
63+
```
64+
65+
## Platform
66+
67+
macOS (uses `open` to auto-play). Linux users: swap `open` for `xdg-open` in `vibe_sing.py`.

SKILL.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
name: vibe-sing
3+
description: Generate a song that captures the vibe of the current Claude Code session. Reads the session transcript, asks Gemini for a non-corny mood prompt, calls Google Lyria, and auto-plays the result. Default is a 30s clip; pass `pro` for a ~2 minute version.
4+
disable-model-invocation: false
5+
argument-hint: [pro]
6+
allowed-tools: Bash
7+
---
8+
9+
When the user invokes `/vibe-sing`, run the pipeline script. It distills the current session's emotional vibe into a Lyria music prompt (via Gemini) and composes a song.
10+
11+
## What to do
12+
13+
1. Run the skill's launcher, passing through the user's argument verbatim:
14+
15+
```bash
16+
~/.claude/skills/vibe-sing/run.sh <arg-if-any>
17+
```
18+
19+
The only meaningful argument is `pro` — generates a ~2 minute song instead of the default 30s clip.
20+
21+
2. The script handles everything: finding the current session's transcript JSONL, slicing the recent vibe-relevant text (skipping tool calls/results), calling Gemini for a mood prompt, calling Lyria, saving the mp3 to `~/.claude/skills/vibe-sing/generations/`, and `open`-ing the file so it plays.
22+
23+
3. After the script returns, the **last line of stdout** is a JSON object with `mood_prompt`, `audio_file`, `model`, and `gemini_model`. Report back to the user in **at most two sentences**:
24+
- One sentence quoting the mood prompt Gemini chose.
25+
- One sentence with the file path.
26+
27+
Do **not** describe what the song is "about" — let the audio speak. Do not add commentary about whether the vibe seems right. The user will hear it and decide.
28+
29+
## Errors
30+
31+
If the script fails (missing `GOOGLE_API_KEY`, no transcript, API error), surface the stderr message verbatim and stop — do not retry.
32+
33+
## Notes
34+
35+
- Requires `GOOGLE_API_KEY` in `.env` inside the skill dir (or in the environment).
36+
- The transcript reader explicitly skips tool calls and tool results to keep the vibe extraction focused on conversational tone.
37+
- Both the transcript filter and the Gemini system prompt are designed to prevent corny "song about debugging React" output — the mood prompt should never reference programming, files, or specific topics.

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
google-genai>=0.3.0
2+
python-dotenv>=1.0.0

run.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4+
PY="$DIR/.venv/bin/python"
5+
if [ ! -x "$PY" ]; then
6+
PY="$(command -v python3 || true)"
7+
fi
8+
if [ -z "$PY" ] || [ ! -x "$PY" ]; then
9+
echo "vibe-sing: no python interpreter found. Create $DIR/.venv (see README)." >&2
10+
exit 1
11+
fi
12+
exec "$PY" "$DIR/vibe_sing.py" "$@"

0 commit comments

Comments
 (0)