Skip to content
Conduit

mcp server

kwami

πŸ‘» kwami.io | A 3D Interactive AI Companion Library for creating engaging AI companions with visual (blob), audio, and AI speech capabilities.

kwami-labs/kwamicommunitylistedunreviewednot running here yet

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 14, 2026

Kwami

License npm npm rc npm dev CI Release Node pnpm

TypeScript ESM types bundle size npm downloads npm downloads total GitHub release GitHub stars

last commit commit activity issues pull requests contributors code size PRs welcome code of conduct

code style: prettier linted with eslint conventional commits semantic-release Vite Vitest Playwright

three.js LiveKit MCP WebGL STT LLM TTS website

Kwami is a browser TypeScript library for 3D AI companions. Drop a canvas on the page, give the companion a soul, and it can speak, listen, remember, and use tools β€” with a WebGL avatar that reacts in real time.

Avatar Β· voice Β· memory Β· tools Β· skills

Site: kwami.io Β· Package: npmjs.com/package/kwami Β· Support: SUPPORT.md


Table of contents


Overview

Each Kwami instance is an independent agent:

PieceWhat it does
AvatarWebGL renderer on an HTMLCanvasElement (blob, black hole, particles, iris)
AgentVoice pipeline over LiveKit β€” STT, LLM, TTS, or realtime
SoulName, personality, emotional traits, and system prompt
MemoryLong-term recall (Zep adapter)
ToolsExternal capabilities via MCP
SkillsNative in-process behaviors

Several instances can share a page. Configuration can change after connect() without tearing the room down.

The avatar is local: new Kwami(canvas) draws immediately. Voice, memory, and tool dispatch need a LiveKit-backed agent and a token endpoint you control β€” the library does not host those for you.

import { Kwami } from 'kwami';

const luna = new Kwami(canvas, {
  soul: { name: 'Luna', personality: 'friendly and creative' },
  agent: { voice: { llm: { model: 'gpt-4o' } } },
});

await luna.connect('user-123', {
  onStateChange: (state) => console.log(state),
  onUserTranscript: (text) => console.log('user:', text),
  onAgentResponse: (text) => console.log('luna:', text),
});

Features

  • 3D avatars β€” blob-xyz, black-hole, particles-face, and eye-iris, with skins, presets, and audio-reactive motion
  • Voice pipeline β€” mix-and-match STT / LLM / TTS, or a realtime provider, dispatched through LiveKit
  • Provider catalog β€” Deepgram, OpenAI, Anthropic, Gemini, ElevenLabs, Groq, Cartesia, AssemblyAI, and more
  • Soul presets β€” ready-made personalities (Kaya, Nexus, Phoenix, Haven, …) plus live trait updates
  • Memory β€” optional long-term context so the companion remembers the user across sessions
  • MCP tools β€” connect Model Context Protocol servers and expose their tools to the agent
  • Skills β€” register native behaviors that run in the page
  • Typed ESM β€” kwami ships as ESM with generated .d.ts; three is a peer dependency

Architecture

                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚              Kwami                  β”‚
                         β”‚  id Β· state Β· connect / disconnect  β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β–Ό          β–Ό           β–Ό       β–Ό        β–Ό          β–Ό
       Avatar      Agent        Soul   Memory   Tools      Skills
      (WebGL)    (LiveKit)   (persona)  (Zep)   (MCP)     (native)
          β”‚          β”‚
          β”‚          └── VoiceSession  STT β†’ LLM β†’ TTS
          └── Scene Β· skins Β· audio bands Β· renderer
ConceptDetail
Constructnew Kwami(canvas, config?) creates avatar, agent, soul, memory, tools, and skills
Connectconnect(userId) initializes memory, builds the system prompt, and dispatches a LiveKit agent
Speak / listenUser speech and agent replies update avatar state: idle β†’ listening β†’ thinking β†’ speaking
Update liveSoul, voice, tools, and skills can change while the room is up
DisposeCall dispose() so the WebGL context, LiveKit room, and registry entry are released

Quick start

pnpm add kwami three

three is a peer dependency. Install it beside kwami; do not rely on a transitive copy.

A WebGL2-capable browser is required. The avatar mounts without a backend; connect() needs a token endpoint and an agent identity your server mints β€” see Connecting.

import { Kwami } from 'kwami';

const canvas = document.querySelector('canvas')!;
const kwami = new Kwami(canvas, {
  soul: { name: 'Kaya', personality: 'A warm, friendly AI companion' },
});

await kwami.connect('user-123');
kwami.sendMessage('Hello β€” who are you?');

// Later
await kwami.disconnect();
kwami.dispose();

Channels:

pnpm add kwami          # latest stable (main)
pnpm add kwami@rc       # release candidate (stg)
pnpm add kwami@dev      # prerelease (dev)

Usage

Soul presets

import { Kwami, getSoulPresetById, toSoulConfig } from 'kwami';

const kaya = getSoulPresetById('friendly');
const kwami = new Kwami(canvas, {
  soul: kaya ? toSoulConfig(kaya) : { name: 'Kaya' },
});

Presets include Kaya, Nexus, Phoenix, Haven, Sage, and others (soulPresets / getSoulPresetsByCategory). Traits can change after connect:

kwami.updateSoul({ emotionalTone: 'enthusiastic' });

Avatar

const kwami = new Kwami(canvas, {
  avatar: { renderer: 'blob-xyz' }, // or 'black-hole' | 'particles-face' | 'eye-iris'
});

Connecting

Pin the agent participant and keep provider keys on the server. The adapter treats that identity as authoritative for audio, transcripts, and tool_call messages.

const kwami = new Kwami(canvas, {
  soul: { name: 'Kaya' },
  agent: {
    livekit: {
      tokenEndpoint: '/api/livekit/token',
      agentIdentity: 'agent-7f3a', // or agentIdentityPrefix: 'kwami-agent:'
    },
  },
});

await kwami.connect('user-123', {
  onStateChange: (state) => {
    /* idle | listening | thinking | speaking */
  },
  onUserTranscript: (text) => {},
  onAgentResponse: (text) => {},
  onError: (error) => console.error(error),
});

Do not put LLM / TTS / STT API keys in the browser. Details: SECURITY.md.

Tools

kwami.registerTool({
  name: 'get_weather',
  description: 'Current weather for a city',
  parameters: {
    type: 'object',
    properties: { city: { type: 'string' } },
    required: ['city'],
  },
  handler: async ({ city }) => fetchWeather(String(city)),
});

MCP servers can be passed in tools.mcp; connect() waits for them before dispatching the agent.

Skills

kwami.skills.register({
  name: 'wave',
  description: 'Play a greeting on the avatar',
  trigger: 'action',
  execute: async ({ kwami: instance }) => {
    // drive the local avatar / UI
    return { success: true, message: 'waved' };
  },
});

Lifecycle

Always dispose() when the canvas leaves the page. Instances stay in a process-wide registry until you do; an unmounted component leaks the WebGL context and the LiveKit room.

await kwami.disconnect();
kwami.dispose();

Getting started

This section is for working on the library. Consumers only need Quick start.

Prerequisites

ToolRequirement
Node.jsVersion in .nvmrc (>= 22.14) β€” nvm use
pnpm>= 10 β€” corepack enable picks up packageManager from package.json

pnpm-lock.yaml is the lockfile of record. CI installs with --frozen-lockfile; an npm install here produces a lockfile CI will reject.

Install

git clone https://github.com/kwami-labs/kwami.git
cd kwami
nvm use
corepack enable
pnpm install    # also installs husky hooks

Build & verify

pnpm build
pnpm lint && pnpm typecheck && pnpm test:run

Scripts

# Build
pnpm build              # bundle + type declarations β†’ dist/
pnpm dev                # rebuild on change
pnpm clean              # remove dist/, coverage/, and test output

# Quality
pnpm lint
pnpm lint:fix
pnpm format
pnpm format:check
pnpm typecheck
pnpm audit:ci

# Tests β€” see docs/testing.md
pnpm test               # unit
pnpm test:watch
pnpm test:coverage      # unit + coverage ratchet (CI)
pnpm test:integration
pnpm test:e2e           # built bundle in a real browser (WebGL)
pnpm test:all

# Releases β€” see docs/releases.md
pnpm release:dry-run    # print next version; change nothing

Project structure

kwami/
β”œβ”€β”€ src/                  # Library source
β”‚   β”œβ”€β”€ agent/            # Voice pipeline, LiveKit adapter, VoiceSession
β”‚   β”œβ”€β”€ avatar/           # WebGL renderers, scene, skins, audio
β”‚   β”œβ”€β”€ memory/           # Memory adapters
β”‚   β”œβ”€β”€ soul/             # Personality and presets
β”‚   β”œβ”€β”€ skills/           # Native behaviors
β”‚   β”œβ”€β”€ tools/            # Tool registry (MCP)
β”‚   β”œβ”€β”€ types/            # TypeScript definitions
β”‚   └── Kwami.ts          # Public entry surface
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ unit/
β”‚   β”œβ”€β”€ integration/
β”‚   └── e2e/
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ ci/               # Pipeline gates
β”‚   └── release/          # Baseline tag, back-merge
β”œβ”€β”€ docs/                 # Deep-dive guides
β”œβ”€β”€ .github/              # Workflows, issue/PR templates, CODEOWNERS
β”œβ”€β”€ CHANGELOG.md          # Generated by semantic-release
β”œβ”€β”€ CODE_OF_CONDUCT.md
β”œβ”€β”€ CONTRIBUTING.md
β”œβ”€β”€ SECURITY.md
β”œβ”€β”€ SUPPORT.md
β”œβ”€β”€ LICENSE               # Apache-2.0
└── package.json

Documentation

DocumentDescription
SUPPORT.mdHow to get help, and what belongs in an issue
CONTRIBUTING.mdSetup, branches, commits, PR checklist
CODE_OF_CONDUCT.mdCommunity standards (Contributor Covenant 2.1)
SECURITY.mdSupported versions & vulnerability reporting
CHANGELOG.mdReleased changes (generated)
docs/ci-cd.mdCI pipeline & promotion gate
docs/releases.mdChannels, version bumps, troubleshooting
docs/testing.mdUnit / integration / e2e layers
LICENSEApache License 2.0 (full text)

Support

Something broken, unclear, or missing? SUPPORT.md is the map β€” questions, bugs, features, and what we cannot debug from an issue (your LiveKit project, provider keys, page wrappers).

Please search existing issues first. Do not paste tokens or API keys.


Contributing

Contributions are welcome. Please read CONTRIBUTING.md and the Code of Conduct before opening a PR.

Branch promotion (enforced in CI):

feature/* ──► dev ──► stg ──► main
  • Branch off dev; open PRs against dev
  • Use Conventional Commits β€” versions, tags, changelog, and npm publishes are derived from them
  • Feature PRs are squash-merged; the PR title becomes the release subject
  • Before push: pnpm lint && pnpm typecheck && pnpm test:unit && pnpm test:integration

Issue tracker: github.com/kwami-labs/kwami/issues


Code of conduct

This project follows the Contributor Covenant. By participating you agree to the CODE_OF_CONDUCT.md.

Reports: alexcollsoutumuro@gmail.com. Do not post accusations in a public issue.


Security

Do not open public issues for vulnerabilities.

Report privately via GitHub Security Advisories or see SECURITY.md for supported versions, scope, and response expectations.


Releases

Releases are automated with semantic-release. Do not hand-edit CHANGELOG.md or the version field.

Branchnpm tagChannel
mainlatestStable
stgrcRelease candidate
devdevPrerelease

Details: docs/releases.md Β· History: CHANGELOG.md


License

Copyright Β© 2025–2026 Alex Colls Outumuro

Licensed under the Apache License, Version 2.0. See the LICENSE file for the full text.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
↑↓ navigate openesc close