Developer Docs
Build a voice skill, or connect your app to a Thalovant hub with an SDK.
There are two things you can build here, and they are different jobs.
A skill runs on the hub and answers a particular kind of request — the code behind “what’s the weather?”. An SDK is a library your own app uses to send requests to a hub and read the answers.
Your First Request New
Section titled “Your First Request ”NewPick the tab for your language. Every SDK does the same four things: sign in, create a client identity on a hub, connect over WSS, ask. The reply’s text is what the hub would have said out loud.
from thalovant import ThalovantClient, ThalovantControlPlane
api = ThalovantControlPlane()
hub = api.list_public_hubs(limit=1)["data"][0]print(hub["title"], hub["slug"])
result = api.create_client_identity( hub["id"], name="python-demo-client", preferred_protocols=("wss", "https", "mqtt"),)
with ThalovantClient(result.identity, protocol="wss") as client: reply = client.ask("Tell me a short clean joke.") print(reply.text)import { ThalovantClient, ThalovantControlPlane } from "@thalovant/sdk";
const api = new ThalovantControlPlane();
const publicHubs = await api.listPublicHubs({ limit: 1 });const [hub] = publicHubs.data as Array<{ id: string; slug: string; title: string }>;console.log(hub.title, hub.slug);
const result = await api.createClientIdentity(hub.id, { name: "node-demo-client", preferredProtocols: ["wss", "https", "mqtt"],});
const client = new ThalovantClient(result.identity, { protocol: "wss" });try { const reply = await client.ask("Tell me a short clean joke."); console.log(reply.text);} finally { await client.close();}package main
import ( "context" "fmt" "log"
thalovant "github.com/thalovant/thalovant-go-sdk")
func main() { ctx := context.Background() control := thalovant.NewDefaultControlPlane("")
if err != nil { log.Fatal(err) }
result, err := control.CreateClientIdentityForHubID(ctx, "hub-id", thalovant.BootstrapIdentityOptions{ Name: "go-demo-client", PreferredProtocols: []thalovant.HubProtocol{ thalovant.ProtocolWSS, thalovant.ProtocolHTTPS, thalovant.ProtocolMQTT, }, }) if err != nil { log.Fatal(err) }
client, err := thalovant.NewClientWithOptions(result.Identity, thalovant.ClientOptions{ Protocol: thalovant.ProtocolWSS, }) if err != nil { log.Fatal(err) } defer client.Close(ctx)
reply, err := client.Ask(ctx, "Tell me a short clean joke.", thalovant.RequestOptions{}) if err != nil { log.Fatal(err) }
fmt.Println(reply.Text)}use thalovant::{ BootstrapIdentityOptions, Client, ControlPlane, HubProtocol, RequestOptions,};
#[tokio::main]async fn main() -> thalovant::Result<()> { let mut control = ControlPlane::default();
let result = control .create_client_identity_for_hub_id( "hub-id", BootstrapIdentityOptions { name: "rust-demo-client".into(), preferred_protocols: vec![HubProtocol::Wss, HubProtocol::Https, HubProtocol::Mqtt], ..Default::default() }, ) .await?;
let client = Client::with_protocol(result.identity.clone(), HubProtocol::Wss)?; let reply = client .ask("Tell me a short clean joke.", RequestOptions::default()) .await; let closed = client.close().await; let reply = reply?; closed?; println!("{}", reply.text);
Ok(())}import com.thalovant.sdk.CreateClientIdentityOptionsimport com.thalovant.sdk.ThalovantClientimport com.thalovant.sdk.ThalovantControlPlaneimport kotlinx.coroutines.runBlocking
fun main() = runBlocking { val api = ThalovantControlPlane()
val result = api.createClientIdentity( "hub-id", CreateClientIdentityOptions(name = "kotlin-demo-client"), )
val client = ThalovantClient(result.identity) try { val reply = client.ask("Tell me a short clean joke.") println(reply.text) } finally { client.close() }}import ThalovantSDK
let api = ThalovantControlPlane()
let result = try await api.createClientIdentity( hubId: "hub-id", options: CreateClientIdentityOptions(name: "swift-demo-client"))
let client = try ThalovantClient(identity: result.identity)do { try await client.connect() let reply = try await client.ask("Tell me a short clean joke.") print(reply.text) await client.close()} catch { await client.close() throw error}using Thalovant;
var api = new ThalovantControlPlane();
var result = await api.CreateClientIdentityAsync( "hub-id", new CreateClientIdentityOptions("dotnet-demo-client"));
using var client = new ThalovantClient(result.Identity);await client.ConnectAsync();var reply = await client.AskAsync("Tell me a short clean joke.");Console.WriteLine(reply.Text);await client.CloseAsync();Each SDK page explains the pieces: where the identity is kept, which protocols the hub accepts, what to pass as context, and how to listen for events.
Building A Skill
Section titled “Building A Skill”Start with the Pocket Quiz tutorial. You can write and test the whole thing on your own computer before you’ve a hub at all. It explains what each file is for and tells you what you should see after every step.
When its checks pass, Add Your Own Skill puts it on a test hub. Then ask it a question out loud, try a follow-up, and check that “stop” ends the game.
Writing a Skill is the reference you’ll reach for afterwards — helpers, conversation rules, tests, packaging. Keep Your Skill Responsive covers caching, bounded service calls, and background refresh.
Connecting Your App
Section titled “Connecting Your App”Thalovant creates the client identity and its access rule; your SDK uses that identity to connect straight to the hub.
- Choose a hub. A public hub is the easiest thing to test against.
- Create a client identity. This needs API access on the workspace.
- Install an SDK. Pick the language your app is already written in.
- Connect over WSS. It’s the default, and every SDK supports it.
- Add HTTPS or MQTT only if you need them. Python, Node.js, Go, and Rust support both once the hub enables them. Kotlin, Swift, and .NET are WSS-only; embedded C uses whatever transport your firmware already has.
- Ask for an SDK origin if you’re in a browser. A customer-owned domain needs review before cross-origin calls are accepted.
- Add context last. User, device, session, and trace metadata are worth adding once the first plain request works.
About The REST API
Section titled “About The REST API”Everything here goes through an SDK, and that’s on purpose. The SDKs are the supported surface: they handle the encrypted, authenticated session, the saved keys a reconnect needs, request correlation, and the retry and cancellation behaviour that a hand-rolled HTTP client has to get right on its own.
There’s no published REST reference, so if you’re looking for one, this is why rather than an omission. Pick the SDK closest to your language — even embedded C, which brings its own transport and leaves the sockets to you.
Connecting An Agent
Section titled “Connecting An Agent”The MCP server exposes hubs to Claude, Codex, Cursor, and other agents as tools, so an agent can ask a hub something or manage skills without you writing a client.