Deploy to SLNG
Start here to create a package, select the organisation, supply credentials,
and deploy or update the agent.
- The trade - what you give up, and what you get back
- What compiling writes - the files, including
tools/andsamples/ - targets.yaml - every key this target takes, and every one it refuses
- The pushed agent’s name - where the deployed name comes from
- Model names - how a vendor and a model are joined
- Push it - deployment and tool resolution
- Tasks and flows - what compiles, and how a task names its tools
- Hosted tool dependencies - only for a package that also targets code
- The Vault - where secrets live, and what a compile can see
- What a slng package may not ask for - the refusals in full
- If the agent answers with silence - where to inspect a failed call
- There is no unmute dev - how to talk to a pushed agent
- Where to go next - the deploy walkthrough
The trade
You author prompts, models, tools, a greeting, and variables. SLNG runs the pipeline and owns its capacity and turn taking. There is no generated Python project or container to maintain. Some package features need a runtime you control. Check the target limits before choosing SLNG.What compiling writes
To stop at the files:tools/ and samples/ folders exist only when the package has a local:
tool. Every other tool reference in agent.json, whether a curated capability,
a hosted tool, or an MCP server, resolves by name against your organisation.
A slng: reference needs no mirror to reach even this point: agent.json
carries the name, and nothing else about the tool.
A local tool on this target
unmute compile wraps the typed handler (handler: tools/<file>.py:<function>)
into one SLNG code tool file. The file holds the handler module, the package’s
state.py when the handler imports from it, and an adapter. The adapter defines
Input from the function signature, Output from the return model, and
handler(input) -> Output.
Three rules apply to a local tool on this target:
- Put a sample beside the tool file:
tools/<name>.sample.json, one JSON object of arguments. SLNG publishes a code tool only after one run, so a local tool with no sample is refused. - Name the function in the handler, as
file.py:function. A handler with no:functionis refused. Anasync defhandler is refused too, because SLNG calls a code tool synchronously. - Expect no internet. SLNG code has no network access. Exact dependency pins come
from the tool’s
dependencies:.
unmute deploy publishes the tool for you. See Deploy to SLNG and
the deploy command.
Validation and compilation run offline. Follow the
deployment guide to install voiceai and push the generated body.
Targets YAML
targets.yaml
targets.<name>. The name selects this target with
--target and names its output folder under build/.
string
required
Use
slng for this target. Omission is refused.string or one-item list of strings
required
Accepts SLNG’s own regions
us-east, us-west, br, eu-west, eu-north, gb, za, il, jp, sg, id, in, au,
and the LiveKit Cloud regions us-east-livekit, eu-central-livekit and ap-south-livekit.
Exactly one region is required; omission, an unknown name, and multiple regions are refused.
The retired any value is refused. These are the agents API’s region names, not the world parts
that speech and the router take, although SLNG’s own are spelled the same.
us-east-livekit is LiveKit Cloud’s US East; SLNG’s own is us-east. The retired codes are
refused with the code to use, as the agents API refuses them: LiveKit Cloud’s eu-central and
ap-south, and SLNG’s us-east-slng. A package that names us-east for LiveKit Cloud, as
packages did before the -livekit suffix, now deploys to SLNG’s own US East.map of model definitions
Overrides keyed by existing model names from
agent.yaml, using the
model fields. Omit to use the package’s models.
An override replaces the entry, except that omitted pace, endpointing_delay,
semantic_endpointing, and prompt_suffix carry forward. An override cannot
author pace or a different prompt_suffix.string
No non-empty value is accepted. Omit it: SLNG owns the runtime version.
map of strings
No non-empty map is accepted. Omit it: there is no generated project whose
dependencies could be pinned.
string
No non-empty value is accepted. Omit it: this target emits no SDK project.
string
No non-empty value is accepted. Omit it: configure the carrier route in SLNG
and attach its trunk at deployment, as described in
phone setup.
integer
Positive and negative values are refused. Omit it: SLNG owns capacity.
Zero also emits no setting.
The pushed agent’s name
The deployed name joins the package’sname: to
its target. A package named my-agent with target slng becomes my-agent-slng.
Deployment resolves an existing agent by name, or uses --agent-id when supplied.
Check the dry run before pushing. See updates and renames
for how to keep or replace an existing deployment.
Model names
SLNG names a model with the vendor and the model joined by a slash. A package writes them as two fields, and the slng driver joins them when it writes the body:agent.yaml
slng/deepgram/nova:3-en reaches the body unchanged.
Model availability depends on your organisation and the selected region.
Follow Choose models and their region
to check the available bindings before deployment.
Push it
Follow Deploy to SLNG to create the package, select an organisation, preview the changes, and push the agent. That guide also covers updates, Vault credentials, and testing a complete interaction. The generatedbuild/slng/README.md lists your package’s requirements. The
deploy command reference describes every flag.
Use unmute deploy for checked deployment. Running voiceai agents push
directly bypasses Unmute’s binding checks and resolved staging.
Where your tools come from
Reference published tools by name withslng:.
This target needs no local mirror. A package that also targets LiveKit or Pipecat
needs unmute pull, because those targets run a local copy of the tool.
Names, not identifiers
agent.json writes each tool and MCP reference as a name, because no compiler
can invent an identifier a server assigns. SLNG’s tool_refs entries require
attachment_id, tool_id and version, so a name has to become an id before
the body is accepted.
This includes a curated capability. A builtin: tool needs nothing created,
because SLNG already has it, and it still has a tool_id that has to be filled
in.
Resolving those names is the push step’s job. It is also why
voiceai agents create --file build/slng/agent.json is the wrong command: that
posts the body verbatim, names included, and the API refuses it.
A webhook: tool never reaches this step: the block is refused before
compiling, for the reason at the top of this page. A local: tool is published
first. unmute deploy creates or updates it as a code tool, runs it once on its
sample, and publishes it. Then this step attaches it by id and version like any
other tool.
An MCP reference resolves the same way, and it needs one thing agent.yaml has to
say up front: which tools you want. Unmute compiles offline, so it cannot expand
“every tool on the server” into a reference list; an mcp: tool with no
mcp.tools list is refused at validate, naming the tool and pointing at
mcp.tools.
Once the list is there, the push looks up the server’s name for its
server_id, then copies each named tool’s schema hash out of the platform’s own
stored capability snapshot. A real unmute deploy can refresh an unusable
snapshot once through voiceai mcp run <server>, then checks it again. A dry
run never refreshes it and reports what needs attention. Discovery does not
execute business tools.
The runbook says which case your package is in.
A push replaces
Updates replace the agent with what the package declares, including its tool attachments and its tasks. A package with no tasks removes tasks somebody built in the dashboard. Preview the changes withunmute deploy --dry-run; follow
Every later deploy for the full sequence.
Tasks and flows
Tasks and flows compile to SLNG’s own tasks, with the same meaning they have on LiveKit and Pipecat:- a task’s
when:,prompt,tools,save:, onestart: say:line,start: listen: true, an outcome withthen: done, and acontext.historyofmessages,full,last_norreset - a flow’s
steps,skip_when_confirmed,context_scopeandthen: return confirm:on a variable, for a task with its ownwhen:- a typed
state.pyvalue that a task saves, including a model, a list, aLiteral, a phone number, an email address, a date or a time
tool_refs, and the push writes SLNG’s
attachment ids in their place. A tool that only a task lists is attached hidden
from the main agent. Every value a task saves becomes a runtime variable, so
its Field in state.py needs a description=.
Do not push a dashboard export back
A dashboard export is not a deployment request. Compile from the authored package, then useunmute deploy to resolve and push the body.
Hosted tool dependencies
SLNG installs the dependencies declared by the published tool. An SLNG-only package needs no local dependency list. LiveKit and Pipecat refuse hosted tools that declare Python dependencies. See Hosted tools before sharing a package across targets.The Vault
SLNG reads secrets from its own store. With your consent,unmute deploy can
fill missing Vault entries through voiceai. The runbook lists what compiling
the package could see, grouped by source, above the push command. No secret value reaches any emitted file or
any command in the runbook.
That list is only what a compile can read offline: a tool’s declared auth:,
and anything a committed mirror recorded. A hosted tool or MCP server’s own credential is not on it, because
SLNG holds that credential and a compile never asks SLNG anything.
unmute deploy reads the account directly and may ask to create an entry the
runbook never named.
Two kinds appear there:
- a secret is a credential a tool authenticates with, named in the package as an environment variable and stored in the Vault under the same name;
- a variable is a
{{$NAME}}token that SLNG substitutes at run time.
{{$NAME}} token into an MCP server URL and nowhere else. A
prompt and a greeting are templates whose placeholder names hold letters,
digits and underscores, so a token written in either is refused when the agent
is pushed. Unmute refuses it at validation instead, on every target, and the
message says what the token is rather than telling you to declare a variable
that must not exist.
For a value your prompt varies per call, declare a package variable and write
{{"{{state.name}}"}}. For a credential, let the tool that needs it name its Vault
entry: a tool’s auth: block names the entry by its bare name, with no
braces and no dollar.
A package that needs no Vault entries is told so, rather than shown an empty
list.
What a slng package may not ask for
Every one of these is refused at validate, by name, with what to do instead. None is dropped quietly.
A package with a
state.py needs uv on PATH to validate and compile, even
when SLNG is its only target, because unmute reads the file by running it. The
first run needs network. A package without a state.py needs no uv.
An MCP tool works when its selected names and discovery snapshot pass the
platform checks. A real deploy may refresh an unusable snapshot once; a dry
run reports it without refreshing.
If the agent answers with silence
A successful deployment does not prove that each provider answers during a call. Follow Verify the agent to test an interaction and Troubleshooting to inspect a failure.There is no unmute dev
unmute dev runs a generated project locally; this target emits no project.
Use the SLNG dashboard to test the deployed agent,
or create a session for your own client.
Where to go next
Speech to text
Which vendors each target accepts, and how SLNG fits in.
Deploy to SLNG
The walkthrough: what you need first, and every failure message.