- Set it up - one command, every assistant
- Check it took - prove the skill loaded
- Read this site as Markdown - the endpoints an assistant fetches
- Build the salon agent - one build, start to finish
- Change an existing package - a different order
- Ask for more - what your request has to carry
- Habits - six things that help
Set it up
You need theunmute binary. See installation.
From the root of your project:
.claude/skills/unmute/SKILL.md is a pointer at the full bundle, so the
instructions exist once no matter how many assistants you set up. Two
assistants in the same project is fine and normal.
Re-run it whenever you upgrade the CLI. It reports what it changed, and it
refuses to overwrite a file you edited by hand unless you pass --force. Full
flags are on the skill command page.
Check it took
A skill that silently did not load looks exactly like an assistant that is bad at Unmute, so prove it before you build anything. A tool is an action the voice agent can call, such as checking appointment slots or booking one. Its YAML file describes what the model may send and has exactly one execution block that says where the action runs. Ask:webhook:, a local: Python handler in the package, and a remote mcp:
server. The other three point at something that already exists. builtin:
selects a tool the runtime already has by id. knowledge: is a search over a
folder of your own documents. slng: is a reference to a tool the SLNG platform
already hosts. A very good answer also mentions the two blocks that exist in the
schema but no target emits.
This question is the check because it cannot be guessed. It is a closed list
out of this project’s own schema, so a model that has not read the skill either
hedges or invents kinds that sound right. If you get a vague paragraph about
function calling, the skill did not load.
When it fails: run unmute skill install again, confirm the directory for your
assistant from the table above exists, and start a new session so the
assistant picks it up.
Read this site as Markdown
The skill teaches an assistant how to write a package. This section is the other half: how an assistant reads the site itself. Every page here is served as Markdown as well as HTML, so an assistant does not have to work from scraped HTML.
Prefer
/llms.txt and then one page. It is a few kilobytes, and it lets the
assistant choose. /llms-full.txt is the entire site in one file, which is
hundreds of kilobytes and will crowd out the rest of a context window.
Every page also carries a menu in its top right corner that copies the page as
Markdown, opens the Markdown, or opens the page in a chat with ChatGPT or
Claude. That is the fastest way to hand one page to an assistant that cannot
fetch a URL itself.
Build the salon agent
This is one build, start to finish. It is the shapeunmute init scaffolds:
one agent, browser audio, local tools, no phone number.
1
Ask in a sentence
2
Read what it wrote
agent.yaml: is channels: what you asked for? A browser agent is
web: realtime_audio and needs no phone route.instructions.md: read it out loud. It should sound like something a
person says, with no bullet lists to read out, no markdown, and no raw
URLs. It should also tell the model how to speak times and names. If it
reads like documentation, the agent will sound like documentation.tools/*.yaml: each tool file has exactly one execution block, and the
description reads as an instruction about when to call it, not as a
label. Local Python handlers are fixtures until you wire them up, and the
assistant should have said so.Use block-style YAML sequences in assistant-authored packages. Do not use anchors or aliases.
This makes every list and task definition readable where it appears. It is
a rule for assistant-written packages, not a claim that Unmute rejects
other valid YAML.3
Add your keys
Create
salon/.env with OPENAI_API_KEY for the model that thinks and
SLNG_API_KEY for the speech models. .env.local is also supported for
local development. unmute dev reads your shell, then .env and
.env.local in the current directory, then both files in the package
directory. Later files win.Which names a package needs is not something to guess at. Every compile
writes salon/build/<target>/.env.example listing the values you supply,
so compile once and read that file.Check: no key, token, or phone number appears in any package file. A
package carries environment variable names only, in UPPER_SNAKE, and the
secrets: block in agent.yaml is where they are declared. If you find a
literal value in the YAML, tell the assistant, because the compiler refuses
them and it should not have written one.4
Let it check its own work
salon you could run unmute validate with no argument and get the
same result. It reports one row per target in targets.yaml, whichever
ones the assistant put there.Ask the assistant to run this itself and fix what it finds. Reading a
refusal is the fastest path it has, and the messages name the file and the
line.Check: warnings are not errors, and they are not noise either. If
validate prints one, the assistant should read it to you rather than move
past it.5
Talk to it
Change an existing package
An existing package needs a different order from a new build. Ask the assistant to keep current behavior until it has separated invalid definitions from unneeded structure:- Inspect the existing package. Read the agent, target, prompt, and loaded tool files before changing them.
- Run
unmute validatebefore editing. Save the errors and warnings as the baseline. - Fix invalid definitions. Make the package legal before changing its structure.
- Simplify. Remove only structure the requested behavior does not need.
- Run
unmute validateagain. Fix every error and report every warning. - Run
unmute compile. Regeneratebuild/from the corrected package.
Ask for more
The build above is one agent with two tools. Everything after it is a conversation with your assistant. What you get back depends on what your request carries. Describe required order, separate roles, and server-directed next steps in plain words. You do not need to ask for tasks or by name. The assistant should infer the smallest Unmute structure before writing files and tell you what it chose.
Ask what it decided, every time. The skill tells it to state the target, the
models, the context across every handoff, and what it actually checked. If any
of those is missing from the answer, ask, because a decision nobody named is a
default nobody chose.
Expect it to refuse things. Unmute does not support every vendor for every role
on every target, and some shapes are gated on some targets. A good answer says
plainly that something is not available and names what is. If your assistant
invents a provider name instead, that is the failure to watch for, and it shows
up as a validation error with the target named.
Habits
Six things that separate a good session from a frustrating one.- Let it run
unmute validateand read the error. Guessing at a schema costs more turns than checking. - Never edit anything under
build/. The next compile overwrites it. Change the package and compile again. - Name the target, or one gets picked for you. Pipecat and LiveKit both compile to a project you run, and they refuse different things.
- Trust the references over what the assistant remembers, and
unmute validateover both. Model memory of a fast moving schema is the single biggest source of confident wrong answers. - Ask what it decided. Structure, target, models, and the context across each task, group, or handoff. A silent default is the bug you find a week later.
- Listen to the agent before you ship it. A green check is not a good call.
Where to go next
How Unmute works
What the compiler did between the package and that container.
Orchestration
Tasks, task groups, and handoffs.
Tools
The five active kinds in full.
Telephony
Put the agent on a real phone number.
Deployment
Get the agent off your laptop.