Skip to content

Ensemble performance space for LLM agents, music models, and humans creating music interactively

Notifications You must be signed in to change notification settings

tobert/hootenanny

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Hootenanny 🎡

An ensemble performance space where AI agents jam together and make music.

Hootenanny exposes music creation tools via MCP, letting Claude, Gemini, and other tool callers generate, arrange, and play music collaboratively. Connect your favorite AI coding assistant and start making music.

✨ What Can You Do?

Generate MIDI β€” Orpheus creates musical sequences from nothing:

orpheus_generate({
  temperature: 1.0,
  max_tokens: 512,
  tags: ["ambient", "exploration"]
})
// β†’ { job_id: "abc123..." }  // Async - poll when ready

Write music in ABC notation β€” Human-readable music β†’ MIDI:

abc_to_midi({
  abc: `X:1
T:Midnight Blues
K:Em
E2 G A B2 | B2 A G E2 |
G2 E D E2 | E4 z2 |`,
  tempo_override: 72,
  transpose: -2
})
// β†’ { artifact_id: "...", content_hash: "..." }

Continue where you left off β€” Extend existing MIDI:

orpheus_continue({
  input_hash: "hash_of_your_midi...",
  temperature: 1.1,
  num_variations: 3
})

Bridge sections β€” Smooth transitions between parts:

orpheus_bridge({
  section_a_hash: "verse_hash...",
  section_b_hash: "chorus_hash...",
  max_tokens: 128
})

Render to audio β€” MIDI + SoundFont β†’ WAV:

midi_render({
  input_hash: "midi_hash...",
  soundfont_hash: "sf2_hash...",
  sample_rate: 44100
})

Play on a timeline β€” DAW-style transport with beat-based timing:

timeline_region_create({
  position: 0,      // Start at beat 0
  duration: 8,      // 8 beats long
  behavior_type: "play_audio",
  content_id: "artifact_123"
})
play({})
tempo({ bpm: 120 })

Detect beats β€” Analyze audio for rhythm:

beats_detect({ audio_hash: "wav_hash..." })
// β†’ Beat positions, downbeats, frame-level activations

Query with Trustfall β€” Find artifacts by lineage, tags, vibes:

graph_query({
  query: `{
    Artifact(tag: "type:midi") {
      id @output
      creator @output
      tags { tag @output @filter(op: "has_substring", value: ["jazzy"]) }
    }
  }`
})

πŸš€ Quick Start

# Clone and build
git clone https://github.com/anthropics/hootenanny
cd hootenanny
cargo build --release

# Start the services
./target/release/hootenanny &   # Control plane (port 5580)
./target/release/holler serve & # MCP gateway (port 8080)
./target/release/chaosgarden &  # Audio daemon

# Configure Claude Code
# Add to your MCP config:
{
  "mcpServers": {
    "holler": {
      "command": "/path/to/holler",
      "args": ["mcp"]
    }
  }
}

Requirements:

  • Rust 1.75+
  • Linux with PipeWire (audio playback)
  • GPU services for generation (Orpheus, etc.) β€” see Infrastructure Setup
  • Python 3.10+ with mido, numpy (for vibeweaver kernel)

πŸ”§ 51 Tools

Organized by prefix for discoverability. Call help() to explore.

Prefix Domain Key Tools
orpheus_* MIDI generation generate, continue, bridge
abc_* ABC notation validate, to_midi
midi_* MIDI operations render, classify, info
audio_* Audio I/O output_attach, input_attach, monitor
musicgen_* Text→audio generate
yue_* Lyrics→song generate
beats_detect Rhythm analysis Beat/downbeat detection
audio_analyze CLAP embeddings Classification, similarity
timeline_* Playback region_create, region_move, clear
play/pause/stop/seek/tempo Transport DAW controls
artifact_* Storage upload, list, get
job_* Async jobs poll, list, cancel
graph_* Queries query, context, bind, connect
kernel_* Python eval, session, reset
config/status/storage_stats System Diagnostics

πŸ— Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           AI Agents                                     β”‚
β”‚              (Claude Code, Gemini, custom MCP clients)                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚ HTTP/SSE (MCP Protocol)
                                 β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                            HOLLER                                       β”‚
β”‚                        MCP ↔ ZMQ Gateway                                β”‚
β”‚  β€’ Routes tool calls to backends    β€’ CLI for manual testing            β”‚
β”‚  β€’ Broadcasts events via SSE        β€’ Dynamic tool discovery            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚ ZMQ (hooteproto / Cap'n Proto)
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β–Ό                 β–Ό                 β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     HOOTENANNY       β”‚ β”‚  VIBEWEAVER β”‚ β”‚         CHAOSGARDEN            β”‚
β”‚   (Control Plane)    β”‚ β”‚  (Python)   β”‚ β”‚      (Realtime Audio)          β”‚
β”‚                      β”‚ β”‚             β”‚ β”‚                                β”‚
β”‚ β€’ Job orchestration  β”‚ β”‚ β€’ Kernel    β”‚ β”‚ β€’ PipeWire integration         β”‚
β”‚ β€’ Artifact store     β”‚ β”‚ β€’ Sessions  β”‚ β”‚ β€’ Timeline playback            β”‚
β”‚ β€’ GPU service calls  β”‚ β”‚ β€’ Rules     β”‚ β”‚ β€’ Beat-synced transport        β”‚
β”‚ β€’ Trustfall queries  β”‚ β”‚             β”‚ β”‚ β€’ Audio graph routing          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚                    β”‚
           β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         GPU SERVICES (HTTP)                               β”‚
β”‚  Orpheus :2000 β”‚ MusicGen :2006 β”‚ CLAP :2007 β”‚ YuE :2008 β”‚ BeatThis :2012 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Crates

Crate Purpose
holler MCP gateway β€” routes HTTP/SSE to ZMQ backends
hootenanny Control plane β€” jobs, artifacts, GPU clients, queries
hooteproto Wire protocol β€” Cap'n Proto schemas over ZMQ
chaosgarden Audio daemon β€” PipeWire, timeline, transport
vibeweaver Python kernel β€” PyO3 embedded interpreter
cas Content-addressed storage β€” BLAKE3 hashing
abc ABC notation parser and MIDI converter
audio-graph-mcp Trustfall adapter for unified queries
hooteconf Layered configuration loading

Key Design Patterns

Async by default β€” Slow tools return job_id immediately:

job = orpheus_generate({...})           // Returns instantly
result = job_poll({                     // Wait for completion
  job_ids: [job.job_id],
  timeout_ms: 60000
})

Content-addressable β€” BLAKE3 hashing, automatic dedup. Share hashes, not bytes.

Artifact-centric β€” Every piece of content gets lineage tracking:

artifact_upload({
  file_path: "/path/to/file.mid",
  mime_type: "audio/midi",
  parent_id: "artifact_that_inspired_this",
  tags: ["variation", "take-2"]
})

Beat-based timing β€” Timeline uses beats, not seconds:

// Position 4 = beat 4, duration 2 = 2 beats
timeline_region_create({ position: 4, duration: 2, ... })

Lazy Pirate β€” Services start in any order. ZMQ handles reconnection.


πŸ›  Development

# Install dependencies
cargo install cargo-watch just

# Run with auto-reload
cargo watch -x 'run -p holler -- serve'

# Run tests
cargo test --workspace

# Build all
cargo build --release

Configuration

Layered config loading: system β†’ user β†’ project β†’ env vars.

# ~/.config/hootenanny/config.toml
[infra.bind]
http_bind_addr = "127.0.0.1:8080"
zmq_router = "tcp://0.0.0.0:5580"

[bootstrap.models]
orpheus = "http://127.0.0.1:2000"
musicgen = "http://127.0.0.1:2006"

[bootstrap.media]
soundfont_dirs = ["~/midi/SF2", "/usr/share/sounds/sf2"]

Adding Tools

  1. Add Cap'n Proto schema in crates/hooteproto/schemas/tools.capnp
  2. Add Rust types in crates/hooteproto/src/request.rs
  3. Implement dispatch in crates/hootenanny/src/api/typed_dispatcher.rs
  4. Register in crates/holler/src/tools_registry.rs

See CLAUDE.md for detailed guidelines.


πŸ“Š Status

Experimental research software exploring human-AI music collaboration. We use it daily β€” expect rough edges.

Working:

  • βœ… MIDI generation (Orpheus: generate, continue, bridge)
  • βœ… ABC notation β†’ MIDI conversion
  • βœ… Audio rendering with SoundFonts
  • βœ… Timeline playback via PipeWire
  • βœ… Async job system with parallel generation
  • βœ… Artifact tracking with lineage
  • βœ… Trustfall queries across the graph
  • βœ… Python kernel for scripting

Evolving:

  • πŸ”„ Multi-agent coordination patterns
  • πŸ”„ Real-time collaboration features
  • πŸ”„ Audio input/recording
  • πŸ”„ MIDI device integration

🀝 Contributing

Built collaboratively with Claude and Gemini. Contributions welcome.

See BOTS.md for coding guidelines β€” the same instructions we give our AI collaborators.


πŸ“œ License

MIT


Contributors: Amy Tobey, πŸ€– Claude, πŸ’Ž Gemini

About

Ensemble performance space for LLM agents, music models, and humans creating music interactively

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •