3
Getting Started
Shinwoo PARK edited this page 2026-05-11 19:50:13 +09:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Getting Started

Setup options

BoxBrain now consumes the published identitydb package from npm, so a sibling checkout of IdentityDB is no longer required for normal usage or local verification.

Use BoxBrain in your own project

bun add boxbrain identitydb

Work on the BoxBrain repository itself

git clone https://git.psw.kr/p-sw/BoxBrain.git
cd BoxBrain
bun install

Verify the repository

bun run test
bun run check
bun run build

If you hit a better-sqlite3 native module / NODE_MODULE_VERSION mismatch after environment changes, reset the install so Bun can re-run trusted lifecycle scripts:

rm -rf node_modules bun.lock
bun install

Runtime requirements

You need:

  • Node.js 20+
  • Bun
  • an initialized IdentityDB database connection at runtime

Create an IdentityDB instance

BoxBrain uses IdentityDB as the persistence layer.

import { IdentityDB } from 'identitydb';

const db = await IdentityDB.connect({
  client: 'sqlite',
  filename: ':memory:',
});

await db.initialize();

For a persistent local database, replace ':memory:' with a file path.

Create model adapters

BoxBrain expects provider adapters instead of hard-coding a vendor into the core runtime.

Provider-agnostic contracts

The package exports these adapter interfaces:

  • TextModelAdapter
  • StructuredModelAdapter
  • ImageModelAdapter
  • SpecialDateProvider

Quick start with Grok

import { createGrokAdapters } from 'boxbrain';

const grok = createGrokAdapters({
  apiKey: process.env.XAI_API_KEY!,
  textModel: 'grok-4.3-mini',
  structuredModel: 'grok-4.3',
  imageModel: 'grok-imagine-image-quality',
});

Initialize a persona

You can use either the functional helper or the class-based service entrypoint.

Functional helper

import { IdentityDB } from 'identitydb';
import { createGrokAdapters, initializePersona } from 'boxbrain';

const db = await IdentityDB.connect({ client: 'sqlite', filename: ':memory:' });
await db.initialize();

const grok = createGrokAdapters({
  apiKey: process.env.XAI_API_KEY!,
  textModel: 'grok-4.3-mini',
  structuredModel: 'grok-4.3',
  imageModel: 'grok-imagine-image-quality',
});

const persona = await initializePersona(db, {
  displayName: 'Mina',
  seedText:
    'Mina is a thoughtful, witty, introverted, and emotionally observant product designer. She was raised in Busan and later moved to Seoul for work. She values loyalty, self-respect, and quiet consistency, loves late-night walks, indie music, and quiet cafés, dislikes performative networking and loud restaurants, and stays especially close to her older brother Jisoo, who is protective but teasing.',
  currentDate: '2026-05-11',
  structuredModel: grok.structured,
  imageModel: grok.image,
  generateProfileImage: true,
});

Class-based service

import { IdentityDB } from 'identitydb';
import { createGrokAdapters, PersonaService } from 'boxbrain';

const db = await IdentityDB.connect({ client: 'sqlite', filename: ':memory:' });
await db.initialize();

const grok = createGrokAdapters({
  apiKey: process.env.XAI_API_KEY!,
  textModel: 'grok-4.3-mini',
  structuredModel: 'grok-4.3',
  imageModel: 'grok-imagine-image-quality',
});

const personas = new PersonaService(db);

const persona = await personas.initialize({
  displayName: 'Mina',
  seedText: 'Mina is a thoughtful, witty Seoul product designer who loves quiet cafés.',
  structuredModel: grok.structured,
});

Generate a schedule

import { generateSchedule } from 'boxbrain';

const schedule = await generateSchedule(db, {
  spaceName: persona.spaceName,
  displayName: persona.displayName,
  currentDate: '2026-05-11',
  scope: 'week',
  timezone: 'Asia/Seoul',
  structuredModel: grok.structured,
  specialDateProvider: {
    async listSpecialDates() {
      return [
        {
          date: '2026-05-15',
          title: 'Teachers Day',
          description: 'A recurring Korean commemorative day.',
        },
      ];
    },
  },
});

console.log(schedule.events);
console.log(schedule.availabilityEntries);

Read or override availability

import { getAvailabilitySnapshot, setAvailabilityStatus } from 'boxbrain';

await setAvailabilityStatus(db, {
  spaceName: persona.spaceName,
  mode: 'do_not_disturb',
  reason: 'studying for an exam',
  effectiveFrom: '2026-05-11T19:00:00.000Z',
  until: '2026-05-11T22:00:00.000Z',
  sourceType: 'manual',
});

const snapshot = await getAvailabilitySnapshot(db, {
  spaceName: persona.spaceName,
  at: '2026-05-11T20:00:00.000Z',
});

console.log(snapshot.current);
console.log(snapshot.next);

Run a conversation turn

BoxBrain separates memory retrieval and response planning into three structured model roles:

  • mandatoryMemoryModel
  • contextualMemoryModel
  • responseModel

You can point all three at the same underlying model if you want.

import { replyToConversation, startConversation } from 'boxbrain';

const proactive = await startConversation(db, {
  spaceName: persona.spaceName,
  counterpartId: 'user:shinwoo',
  counterpartDisplayName: 'Shinwoo',
  currentTime: '2026-05-11T12:00:00.000Z',
  mandatoryMemoryModel: grok.structured,
  contextualMemoryModel: grok.structured,
  responseModel: grok.structured,
});

console.log(proactive.messages);

const reply = await replyToConversation(db, {
  spaceName: persona.spaceName,
  counterpartId: 'user:shinwoo',
  counterpartDisplayName: 'Shinwoo',
  currentTime: '2026-05-11T12:05:00.000Z',
  message: 'Are you free tonight?',
  mandatoryMemoryModel: grok.structured,
  contextualMemoryModel: grok.structured,
  responseModel: grok.structured,
});

console.log(reply.blocked);
console.log(reply.messages);
console.log(reply.usedMemories);
console.log(reply.toolCallsExecuted);

Timing helpers

import {
  ONLINE_AVAILABILITY,
  createReplyDelay,
  createTypingDelay,
} from 'boxbrain';

const replyDelay = createReplyDelay(ONLINE_AVAILABILITY, {
  isFirstReplyInExchange: true,
});

const typingDelay = createTypingDelay('지금 뭐해?', {
  minSecondsPerCharacter: 0.05,
  maxSecondsPerCharacter: 0.08,
});

Important caveats

1. BoxBrain is a library, not an HTTP service

You call the exported TypeScript APIs directly.

2. IdentityDB is a required runtime dependency

The framework assumes IdentityDB is available and initialized.

3. Internal source folders are a repository concern

The repository is organized by domain folders under src/, but the published package is still consumed through the package root exports.

4. Clean Bun installs depend on trusted lifecycle scripts

The repository keeps trustedDependencies for better-sqlite3 and esbuild so native/runtime build steps succeed during clean installs.