SDKs
Official client libraries for MUXI
Native SDKs for 12 languages. Build custom UIs, manage user credentials, handle observability events, and control formations programmatically.
Why Use the SDKs?
The SDKs are how developers build products on top of MUXI:
| Use Case | What SDKs Enable |
|---|---|
| Custom Chat UIs | Build your own chat interface instead of using the default |
| Credential Management | Let users add API keys/tokens via your UI (not via chat) |
| Observability Dashboards | Subscribe to 350+ event types for monitoring and debugging |
| User Management | Manage scheduled tasks, memory, and sessions per user |
| Formation Control | Deploy, start, stop, restart formations programmatically |
Security note: When user credentials are required for tools (GitHub, Gmail, etc.), developers can configure whether users provide them via chat or via a dedicated credentials page. The SDK lets you build that credentials page.
Quick Install
Python
Works in scripts, servers, notebooks, and serverless. Python 3.10+
pip install muxi-sdk
Learn more & install โบ
TypeScript
Works on your server (Node.js/Bun), in your browsers, and edge.
npm install @muxi/sdk
Learn more & install โบ
Go
Works in services, CLIs, serverless, and embedded systems.
go get github.com/muxi-ai/muxi-go
Learn more & install โบ
Quick Start
from muxi import FormationClient
client = FormationClient(
server_url="http://localhost:7890",
formation_id="my-assistant",
client_key="your_client_key",
)
for event in client.chat_stream({"message": "Hello!"}):
if event.get("type") == "text":
print(event.get("text"), end="")
import { FormationClient } from "@muxi-ai/muxi-typescript";
const client = new FormationClient({
serverUrl: "http://localhost:7890",
formationId: "my-assistant",
clientKey: "your_client_key",
});
for await (const event of client.chatStream({ message: "Hello!" })) {
if (event.type === "text") process.stdout.write(event.text);
}
client := muxi.NewFormationClient(&muxi.FormationConfig{
ServerURL: "http://localhost:7890",
FormationID: "my-assistant",
ClientKey: "your_client_key",
})
stream, _ := client.ChatStream(ctx, &muxi.ChatRequest{Message: "Hello!"})
for chunk := range stream {
if chunk.Type == "text" {
fmt.Print(chunk.Text)
}
}
require 'muxi'
client = Muxi::FormationClient.new(
server_url: 'http://localhost:7890',
formation_id: 'my-assistant',
client_key: 'your_client_key'
)
client.chat_stream(message: 'Hello!') do |event|
print event['text'] if event['type'] == 'text'
end
FormationClient client = new FormationClient(
"http://localhost:7890",
"my-assistant",
"your_client_key"
);
client.chatStream(new ChatRequest("Hello!"), event -> {
if ("text".equals(event.getType())) {
System.out.print(event.getText());
}
return true;
});
val client = FormationClient(
serverUrl = "http://localhost:7890",
formationId = "my-assistant",
clientKey = "your_client_key"
)
client.chatStream(ChatRequest(message = "Hello!")).collect { event ->
if (event.type == "text") print(event.text)
}
let client = FormationClient(
serverURL: "http://localhost:7890",
formationID: "my-assistant",
clientKey: "your_client_key"
)
for try await event in client.chatStream(message: "Hello!") {
if event.type == "text" { print(event.text ?? "", terminator: "") }
}
var client = new FormationClient(
serverUrl: "http://localhost:7890",
formationId: "my-assistant",
clientKey: "your_client_key"
);
await foreach (var chunk in client.ChatStreamAsync(new ChatRequest { Message = "Hello!" }))
{
if (chunk.Type == "text") Console.Write(chunk.Text);
}
$client = new FormationClient(
serverUrl: 'http://localhost:7890',
formationId: 'my-assistant',
clientKey: 'your_client_key'
);
foreach ($client->chatStream(['message' => 'Hello!']) as $event) {
if ($event['type'] === 'text') echo $event['text'];
}
final client = FormationClient(
serverUrl: 'http://localhost:7890',
formationId: 'my-assistant',
clientKey: 'your_client_key',
);
await for (final event in client.chatStream(message: 'Hello!')) {
if (event['type'] == 'text') stdout.write(event['text']);
}
let client = FormationClient::new(
"http://localhost:7890",
"my-assistant",
"your_client_key",
);
let mut stream = client.chat_stream("Hello!").await?;
while let Some(event) = stream.next().await {
if event?.event_type == "text" { print!("{}", event.text.unwrap_or_default()); }
}
auto client = muxi::FormationClient(
"http://localhost:7890",
"my-assistant",
"your_client_key"
);
client.chat_stream({{"message", "Hello!"}}, [](sdks/const auto& event) {
if (event.type == "text") std::cout << event.text;
return true;
});
Local Development
When developing locally with muxi up, use the mode="draft" parameter to route requests through the /draft/ endpoint on your local MUXI server. This allows you to test changes without affecting your live deployment:
client = FormationClient(
server_url="http://localhost:7890",
formation_id="my-assistant",
mode="draft", # Uses /draft/ prefix
client_key="your_client_key",
)
const client = new FormationClient({
serverUrl: "http://localhost:7890",
formationId: "my-assistant",
mode: "draft", // Uses /draft/ prefix
clientKey: "your_client_key",
});
client := muxi.NewFormationClient(&muxi.FormationConfig{
ServerURL: "http://localhost:7890",
FormationID: "my-assistant",
Mode: "draft", // Uses /draft/ prefix
ClientKey: "your_client_key",
})
client = Muxi::FormationClient.new(
server_url: 'http://localhost:7890',
formation_id: 'my-assistant',
mode: 'draft', # Uses /draft/ prefix
client_key: 'your_client_key'
)
FormationClient client = new FormationClient(
"http://localhost:7890",
"my-assistant",
"your_client_key",
"draft" // Uses /draft/ prefix
);
val client = FormationClient(
serverUrl = "http://localhost:7890",
formationId = "my-assistant",
mode = "draft", // Uses /draft/ prefix
clientKey = "your_client_key"
)
let client = FormationClient(
serverURL: "http://localhost:7890",
formationID: "my-assistant",
mode: "draft", // Uses /draft/ prefix
clientKey: "your_client_key"
)
var client = new FormationClient(
serverUrl: "http://localhost:7890",
formationId: "my-assistant",
mode: "draft", // Uses /draft/ prefix
clientKey: "your_client_key"
);
$client = new FormationClient(
serverUrl: 'http://localhost:7890',
formationId: 'my-assistant',
mode: 'draft', // Uses /draft/ prefix
clientKey: 'your_client_key'
);
final client = FormationClient(
serverUrl: 'http://localhost:7890',
formationId: 'my-assistant',
mode: 'draft', // Uses /draft/ prefix
clientKey: 'your_client_key',
);
let client = FormationClient::new(
"http://localhost:7890",
"my-assistant",
"your_client_key",
).with_mode("draft"); // Uses /draft/ prefix
auto client = muxi::FormationClient(
"http://localhost:7890",
"my-assistant",
"your_client_key",
"draft" // Uses /draft/ prefix
);
Workflow:
- Run
muxi upto start your formation in draft mode - Use
mode="draft"in your SDK client during development - Run
muxi deployto deploy to production - Remove
mode="draft"(or don't set it) - defaults tomode="live"which uses/api/
The mode parameter only affects URL routing. All other functionality is identical between draft and live modes.
Two Client Types
All SDKs provide two clients:
FormationClient
For interacting with a running formation:
- Chat (streaming & non-streaming)
- Sessions & history
- Memory management
- Triggers & scheduled tasks
- Agent configuration
Authentication: Client key (X-Muxi-Client-Key) or Admin key (X-Muxi-Admin-Key)
Browser usage: The TypeScript SDK's FormationClient works directly in browsers. Use the clientKey for browser apps - it's safe to expose and has limited permissions. Keep the adminKey server-side only.
ServerClient
For managing the MUXI server:
- Deploy formations
- Start/stop/restart formations
- List formations
- Server health & logs
Authentication: HMAC signature (key_id + secret_key)
Common Operations
Chat (Streaming)
for event in formation.chat_stream({"message": "Hello!"}, user_id="user_123"):
if event.get("type") == "text":
print(event.get("text"), end="")
elif event.get("type") == "done":
break
for await (const chunk of await formation.chatStream({ message: "Hello!" }, "user_123")) {
if (chunk.type === "text") process.stdout.write(chunk.text);
if (chunk.type === "done") break;
}
stream, errs := client.ChatStream(ctx, &muxi.ChatRequest{Message: "Hello!", UserID: "user_123"})
for chunk := range stream {
if chunk.Type == "text" {
fmt.Print(chunk.Text)
}
}
Memory
# Get memories
memories = formation.get_memories(user_id="user_123")
# Add memory (user_id, mem_type, detail)
formation.add_memory(user_id="user_123", mem_type="preference", detail="User prefers Python")
# Clear buffer
formation.clear_user_buffer(user_id="user_123")
// Get memories
const memories = await formation.getMemories("user_123");
// Add memory (userId, type, detail)
await formation.addMemory("user_123", "preference", "User prefers TypeScript");
// Clear buffer
await formation.clearUserBuffer("user_123");
// Get memories
memories, _ := client.GetMemories(ctx, "user_123")
// Add memory (ctx, userId, type, detail)
client.AddMemory(ctx, "user_123", "preference", "User prefers Go")
// Clear buffer
client.ClearUserBuffer(ctx, "user_123")
Server Management
from muxi import ServerClient
server = ServerClient(
url="http://localhost:7890",
key_id="muxi_pk_...",
secret_key="muxi_sk_...",
)
# Deploy
server.deploy_formation(bundle_path="my-bot.tar.gz")
# List formations
formations = server.list_formations()
# Stop/start/restart
server.stop_formation(formation_id="my-bot")
server.start_formation(formation_id="my-bot")
import { ServerClient } from "@muxi-ai/muxi-typescript";
const server = new ServerClient({
url: "http://localhost:7890",
keyId: "muxi_pk_...",
secretKey: "muxi_sk_...",
});
// Deploy
await server.deployFormation({ bundlePath: "my-bot.tar.gz" });
// List formations
const formations = await server.listFormations();
// Stop/start/restart
await server.stopFormation("my-bot");
await server.startFormation("my-bot");
server := muxi.NewServerClient(&muxi.ServerConfig{
URL: "http://localhost:7890",
KeyID: "muxi_pk_...",
SecretKey: "muxi_sk_...",
})
// Deploy
server.DeployFormation(ctx, &muxi.DeployRequest{BundlePath: "my-bot.tar.gz"})
// List formations
formations, _ := server.ListFormations(ctx)
// Stop/start/restart
server.StopFormation(ctx, "my-bot")
server.StartFormation(ctx, "my-bot")
Multi-Identity Users
Link multiple identifiers (email, Slack ID, etc.) to a single user:
# Link email, Slack ID, and internal ID to same user
result = formation.associate_user_identifiers(
identifiers=[
"alice@email.com",
{"identifier": "U12345ABC", "type": "slack"},
("user_123", "internal"),
],
user_id=None, # Create new user (or pass existing user ID)
)
print(f"User ID: {result['muxi_user_id']}")
# Now all identifiers resolve to the same user
formation.chat("Hello", user_id="alice@email.com") # Same user
formation.chat("Hello", user_id="U12345ABC") # Same user
formation.chat("Hello", user_id="user_123") # Same user
// Link identifiers to same user
const result = await formation.associateUserIdentifiers({
identifiers: [
"alice@email.com",
{ identifier: "U12345ABC", type: "slack" },
],
userId: null, // Create new user
});
console.log(User ID: ${result.muxiUserId});
result, _ := client.AssociateUserIdentifiers(ctx, &muxi.AssociateRequest{
Identifiers: []interface{}{
"alice@email.com",
muxi.TypedIdentifier{Identifier: "U12345ABC", Type: "slack"},
},
UserID: nil,
})
fmt.Printf("User ID: %s
", result.MuxiUserID)
Why? Users interact via multiple channels (Slack, email, web). Multi-identity ensures they get the same memory and context everywhere.
Learn more: Multi-Identity Users โ
Session Restore
Restore conversation history from your external storage:
# Restore session from your database
messages = your_db.get_messages(session_id="sess_abc123")
formation.restore_session(
session_id="sess_abc123",
messages=[
{"role": "user", "content": "Hello", "timestamp": "..."},
{"role": "assistant", "content": "Hi!", "timestamp": "..."},
],
user_id="alice@email.com"
)
# User continues with full context
await formation.restoreSession({
sessionId: "sess_abc123",
messages: [
{ role: "user", content: "Hello", timestamp: "..." },
{ role: "assistant", content: "Hi!", timestamp: "..." },
],
userId: "alice@email.com",
});
client.RestoreSession(ctx, &muxi.RestoreRequest{
SessionID: "sess_abc123",
Messages: []muxi.Message{
{Role: "user", Content: "Hello", Timestamp: "..."},
{Role: "assistant", Content: "Hi!", Timestamp: "..."},
},
UserID: "alice@email.com",
})
Why? MUXI's buffer is ephemeral. For persistent chat history (like ChatGPT's sidebar), persist messages yourself and restore when users return.
Error Handling
All SDKs provide typed errors:
| Error | Meaning |
|---|---|
AuthenticationError
| Invalid API key |
AuthorizationError
| Insufficient permissions |
NotFoundError
| Resource doesn't exist |
ValidationError
| Invalid request data |
RateLimitError
| Too many requests |
ServerError
| Server-side error |
ConnectionError
| Network issue |
from muxi import MuxiError, AuthenticationError, RateLimitError
try:
response = formation.chat_stream({"message": "Hello!"}, user_id="user_123")
except AuthenticationError:
print("Invalid API key")
except RateLimitError as e:
print(f"Rate limited, retry after {e.retry_after}s")
except MuxiError as e:
print(f"Error: {e.code} - {e.message}")
import { MuxiError, AuthenticationError, RateLimitError } from "@muxi-ai/muxi-typescript";
try {
await formation.chatStream({ message: "Hello!" }, "user_123");
} catch (err) {
if (err instanceof AuthenticationError) {
console.log("Invalid API key");
} else if (err instanceof RateLimitError) {
console.log(Rate limited, retry after ${err.retryAfter}s);
} else if (err instanceof MuxiError) {
console.log(Error: ${err.code} - ${err.message});
}
}
resp, err := client.Chat(ctx, &muxi.ChatRequest{Message: "Hello!", UserID: "u1"})
if err != nil {
var authErr *muxi.AuthenticationError
var rateLimit *muxi.RateLimitError
switch {
case errors.As(err, &authErr):
log.Println("Invalid API key")
case errors.As(err, &rateLimit):
log.Printf("Rate limited, retry after %d seconds", rateLimit.RetryAfter)
default:
log.Fatal(err)
}
}
Configuration
| Setting | Python | TypeScript | Go | Default |
|---|---|---|---|---|
| Timeout | timeout=30
| timeout: 30000
| 30s built-in | 30s |
| Retries | max_retries=3
| maxRetries: 3
| 3 built-in | 3 |
| Debug | debug=True
| debug: true
| - | Off |
Learn More
- Python SDK โ
- TypeScript SDK โ
- Go SDK โ
- Ruby SDK โ
- PHP SDK โ
- C# SDK โ
- Java SDK โ
- Kotlin SDK โ
- Swift SDK โ
- Dart SDK โ
- Rust SDK โ
- C++ SDK โ
Reference: