foley
Find (or generate) the right sound effect for a moment of narration — and weave it in.
foley is a retrieval-first façade for sound effects: one simple surface over many sound sources (your own library, service APIs, and generative-AI models), a searchable index of every sound (by keyword and meaning), an agent that picks the right sound for a narrative context, and a compositor that places it under the voice.
It's the SFX sibling of arioso (a unified
façade over AI music-generation backends): same discipline — one entry function,
config-driven plugin adapters, a unified vocabulary translated per-backend, zero
required core deps with lazy optional-deps — but centered on search rather than
generation, with generation as just one of several sources.
Status: v1. All four stages — source, index, select, weave — plus the MCP server and the licensing/provenance, evaluation, and observability layers are implemented (Epic #13 complete). The API below is live; see the roadmap for what's next. Follow along in
misc/docs/.
The idea
import foley
# The headline — right sounds for a narrative context:
# decompose the passage into salient sound events → search → verify → decide
candidates = foley.find("She pushed open the heavy oak door; rain hammered outside.")
# Direct hybrid search of your library (text query or a reference clip)
hits = foley.search("distant thunder rumble", k=10) # commercial use is the default
# Generate a sound when nothing fits (arioso-style; pluggable backends)
clip = foley.generate("a single wooden door creak", backend="stable_audio", duration=3)
# Grow the library — ingest auto-tags, captions, and embeds every file
foley.ingest("~/my_sounds/", license="user-owned") # omit it and rights stay unknown
foley.add_from("freesound", query="ocean waves", license="cc0")
# Compose: place the sounds under the narration (find → plan → weave)
timeline = foley.plan(candidates) # the editable sound-design plan
result = foley.weave("narration.wav", timeline) # mastered mix + SDH captions + credits
How it works — four stages
| Stage | What it does | Built on |
|---|---|---|
| Source | your own files · Freesound (CC0) · generate (Stable Audio Open / ElevenLabs) | config-driven adapters, per-sound license tracking |
| Index | probe → tag → caption → embed every sound; hybrid keyword+semantic search | PANNs · CLAP · EnCLAP · LanceDB (local→cloud via dol) |
| Select | decompose a narrative context → search → verify → generate-or-retrieve | CLAP retrieval + LLM decomposition + a verification ladder |
| Weave | align to the voice, duck, place, master → mastered mix + editable timeline + captions + credits | forced-alignment · LUFS/EBU-R128 |
The selection tools publish as an MCP server (via py2mcp) so the same capabilities
drive the agent, a CLI, and external hosts.
For AI agents
foley is AI-first: most callers are agents (directly, and via downstream packages like
braidio and nw). The headline is one call — hand it narration text and it chooses tasteful,
license-clean sounds and (given the audio) weaves them in:
import foley
# Plan only — choose sounds, get an editable timeline + a rationale:
result = foley.score("She pushed open the heavy oak door; rain hammered outside.")
print(result.rationale)
# Plan + render — weave under the actual narration audio:
result = foley.score(segments, audio="narration.wav", commercial_ok=True)
result.weave.audio # mastered mix result.weave.captions_vtt # SDH captions
result.weave.credits # attribution result.timeline # still editable
foley.score(...) is the stable contract braidio/nw call. The same surface is available as
MCP tools (foley_score, foley_guide, foley_search, foley_preview, foley_weave, …) —
serve them over stdio (foley-mcp) or authenticated HTTP (foley-mcp --http --token …).
Ship the agent kit into your agent host (a foley-sound-design skill, a /foley-score
slash command, and a sound-designer subagent):
foley agent-install # → ./.claude/{skills,commands,agents}/…
The one rule is restraint — most sentences need no sound. The design is grounded in the research reports below; taste heuristics (layering, ducking, onset, licensing) live in the skill.
Design & research
foley's design is grounded in five research reports (unified, cited):
- Design · Roadmap
- Research reports — sound sources, SFX generation, recognition/ tagging, embeddings/indexing, and the context-retrieval agent
- Deep-research prompt library — 12 ready-to-run prompts covering every dimension of the project
Install
pip install foley # core — dol-only, light; `import foley` stays minimal
pip install "foley[audio,clap,index]" # the usual retrieval stack (CLAP + hybrid index)
foley demo # no-download smoke test on the bundled fixture
foley agent-install # drop the agent kit into ./.claude (skill + command + subagent)
foley is zero-dep at its core and grows by capability via optional extras — each imported lazily, so a bare install stays light. What each adds:
| Extra | Adds |
|---|---|
audio |
numpy/soundfile DSP + LUFS mastering |
clap |
the CLAP text↔audio retrieval engine |
index / index-sqlite |
the hybrid vector+keyword index (LanceDB / sqlite-vec) |
freesound · stable-audio · elevenlabs |
live retrieve / generate sources |
agent · local-llm |
the SELECT LLM rungs (Claude / a local OpenAI-compatible endpoint) |
align · weave · provenance · c2pa |
forced alignment, OTIO/rubberband, watermarking, signed C2PA |
mcp · obs |
the MCP server · OpenTelemetry export |
Nothing paid runs unless you ask for it. Having ANTHROPIC_API_KEY set does not switch the SELECT rungs to Claude: pass llm="anthropic" to find() / score() or set FOLEY_LLM=anthropic (llm="local" uses FOLEY_LLM_BASE_URL). By default they run the free deterministic fakes, or your local endpoint if one is configured. with foley.offline(): (or FOLEY_OFFLINE=1) blocks every external source and LLM call foley makes, on every surface, raising foley.runtime.EgressBlocked (model-weight downloads from Hugging Face are not covered yet).
foley.check_requirements() (and the foley_capabilities MCP tool) report what's installed and
what's degraded. Full docs: thorwhalen.github.io/foley.
Changelog
Per-release changes are in CHANGELOG.md.
License
MIT
Metadata
Release files for foley 0.0.30
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| foley-0.0.30.tar.gz | 701.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| foley-0.0.30-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / foley-0.0.30.tar.gz
| Download URL | foley-0.0.30.tar.gz |
|---|---|
| Size | 701.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
72d735262e8b66d79533e693dc8086fcf59cd9c0883bf378908c312c6deb737e
|
|
BLAKE2b-256 checksum How to use checksums |
c08ded143f63aed5c98965c8c39c045712e833d9010ccb4f0662bfed44f18e88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / foley-0.0.30-py3-none-any.whl
| Download URL | foley-0.0.30-py3-none-any.whl |
|---|---|
| Size | 403.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2df46cdea9f56953366de9de26df3dd41c06e0199e0da433f2d725196bfab8b1
|
|
BLAKE2b-256 checksum How to use checksums |
d9d23a166a5c5920079a370eddf9fafd5612f19d24763919245d6b8ea12acb30
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|