Step-by-step tutorial to generate a character, create an NPC, and chat with it via the SDK or CLI.
Create Your First NPC
This tutorial walks you through creating an AI-powered NPC from scratch. You'll generate a character with AI, turn it into an NPC, list chat threads, and start chatting—using either the SDK or the CLI.
Prerequisites
1. Install pu-client
npm install pu-clientpnpm add pu-clientyarn add pu-client2. Get your API key
- Sign in at upstreet.ai
- Go to Account > Developer
- Copy your API key and set it in your environment:
export PU_API_KEY="your-api-key-here"Step-by-Step Tutorial
1. Create the client and generate a character
import { PUClient } from 'pu-client';
const client = new PUClient({ apiKey: process.env.PU_API_KEY! });
const genId = await client.generations.create({
type: 'character',
input: { prompt: 'A friendly fox merchant with a backpack', smartPrompt: true },
});2. Wait for the generation to complete
Poll until the state is done or error:
let gen = await client.generations.get(genId);
while (gen.state !== 'done' && gen.state !== 'error') {
await new Promise(r => setTimeout(r, 2000));
gen = await client.generations.get(genId);
}
if (gen.state === 'error') {
throw new Error(gen.error ?? 'Generation failed');
}3. Create the NPC
Use the character ID from the generation output. The src format is characterlive:uuid:
const characterId = gen.output?.character_id;
if (!characterId) throw new Error('No character in output');
const npc = await client.npcs.create({
name: 'Fox Merchant',
src: `characterlive:${characterId}`,
});
console.log(`NPC created: ${npc.name} (${npc.id})`);4. List chat threads
const threads = await client.npcs.listThreads(npc.id);
console.log(`Threads: ${threads.length}`);
threads.forEach(t => console.log(` - ${t.title} (${t.id})`));5. Chat with the NPC
Use the web app at /npcs/[id]/chat, or programmatically via the chat API. For a quick terminal chat, use the CLI: puc npc chat <npcId>.
1. Generate a character
puc character create -p "A friendly fox merchant with a backpack" --smartPromptThe command prints the generation ID. When complete, it outputs the character ID (or you can fetch it via puc generations get <id> --json).
2. Create the NPC
Use the character ID with the characterlive: prefix:
puc npc create --name "Fox Merchant" --src "characterlive:<character-uuid>"3. List threads and chat
puc npc list
puc npc chat <npc-id>Start an interactive chat session in the terminal.
Full SDK Example
import { PUClient } from 'pu-client';
async function createFirstNPC() {
const client = new PUClient({ apiKey: process.env.PU_API_KEY! });
const genId = await client.generations.create({
type: 'character',
input: { prompt: 'A wise owl wizard', smartPrompt: true },
});
let gen = await client.generations.get(genId);
while (gen.state !== 'done' && gen.state !== 'error') {
await new Promise(r => setTimeout(r, 2000));
gen = await client.generations.get(genId);
}
if (gen.state === 'error') throw new Error(gen.error ?? 'Generation failed');
const characterId = gen.output?.character_id;
if (!characterId) throw new Error('No character in output');
const npc = await client.npcs.create({
name: 'Owl Wizard',
src: `characterlive:${characterId}`,
});
const threads = await client.npcs.listThreads(npc.id);
console.log(`NPC "${npc.name}" ready. Threads: ${threads.length}`);
return npc;
}