# BoxBrain BoxBrain is a TypeScript framework for designing LLM harnesses that make a persona feel like a real person, backed by IdentityDB memory spaces. This repository was reset from scratch. The current implementation focuses on a clean framework core rather than a concrete chatbot product. ## Goals BoxBrain helps API users build an LLM-driven persona with: - persona initialization into an isolated IdentityDB-backed space - realistic schedule generation - schedule-derived availability (`online`, `do-not-disturb`, `offline`) - reply and proactive conversation APIs - sleep-time memory extraction into durable facts - debug hooks that expose the framework flow and persona reasoning pipeline ## Install ```bash bun install ``` ## Core API ```ts import { Persona, createSqliteIdentityMemoryStore } from 'boxbrain'; const memory = await createSqliteIdentityMemoryStore('.data/mina.sqlite'); const persona = new Persona( 'Mina', 'Mina is a careful student who likes quiet cafes and is preparing for exams.', { memory, models: { conversation: yourConversationModel, memoryExtraction: yourMemoryExtractionModel, }, debug: (event) => console.log(event), }, ); const space = await persona.ready(); ``` A persona can also be loaded from an existing space: ```ts const persona = new Persona(space.id, { memory, models }); await persona.ready(); ``` ## Persona initialization `new Persona(displayName, message, options)` creates a new isolated persona space. The seed message is the single freeform place for personality, history, likes, dislikes, relationships, and other facts about the persona. `new Persona(spaceId, options)` loads an existing persona space. If `models.initialization` is provided, BoxBrain asks it for initial facts. If no initialization model is provided, BoxBrain stores a minimal seed fact about the persona. If the model intentionally returns an empty list, no fallback fact is stored. ## Schedule API ```ts await persona.createDailySchedule(now, 'Keep a normal work day.'); await persona.createMonthlySchedule(now, 'Mostly study, with occasional rest.'); await persona.deleteSchedulesBefore(cutoff); await persona.deleteSchedulesOlderThan(cutoff); ``` `createDailySchedule(datetime, message)` creates tomorrow's schedule in 10-minute blocks. For example, if `datetime` is May 1, the generated daily schedule covers May 2 00:00 through May 3 00:00. `createMonthlySchedule(datetime, message)` creates day-level schedule outlines for the next 30 days. Schedules are stored through the configured memory store. The IdentityDB store records schedule entries as facts under schedule-related topics. ## Availability API ```ts const availability = await persona.getTodayScheduledAvailability(now); ``` Availability is derived from schedule entries and kept in memory rather than persisted separately. The window covers today 00:00 through tomorrow 24:00. When the date changes, BoxBrain rebuilds the snapshot from schedule entries in memory. Schedule activities map to availability roughly as: - `sleep` → `offline` - `work`, `study`, `job-search`, `travel`, `commute` → `do-not-disturb` - rest, meals, exercise, errands, social time, free time → `online` ## Conversation API ```ts const reply = await persona.sendMessage({ datetime: now, messageHistory: [ { sender: 'persona', time: yesterday, content: 'See you later.' }, { sender: 'user', time: now, content: 'What are you doing?' }, ], }); const opener = await persona.startConversation({ datetime: now, messageHistory: [], }); ``` Before generating a reply, BoxBrain always loads mandatory context: - formatted yesterday/today message history supplied by the API user - yesterday, today, and tomorrow schedule entries - current schedule-derived availability - IdentityDB facts related to the persona and the user If no relevant mandatory memory is found, the model context explicitly says `기억이 없음` so the persona can react naturally instead of pretending to remember. Conversation models return one or more outgoing messages. The framework instruction tells the model to behave like a `send_message` tool and, unless the persona prefers otherwise, keep each message to at most one sentence. If `getLatestMessageHistory` and `models.rewrite` are provided, BoxBrain can detect messages that arrived while a draft was being generated and ask the rewrite model whether to discard and regenerate the stale draft. ## sleepMemory ```ts await persona.sleepMemory({ datetime: '2026-05-02T00:00:00.000Z', messageHistory: messagesFromMay1, }); ``` `sleepMemory` asks `models.memoryExtraction` to inspect the provided message history, objectivize durable facts, and persist them through the memory store. The recommended cadence is daily around midnight, passing the previous day's messages. ## Debug hooks Every major pipeline step can emit a debug event: ```ts const persona = new Persona('Mina', seed, { debug(event) { // Write to a file, messenger, trace UI, etc. console.log(event.name, event.data); }, }); ``` Examples include: - `persona.initialized` - `persona.loaded` - `persona.schedule.daily.generated` - `persona.availability.refreshed` - `persona.conversation.context.loaded` - `persona.conversation.rewrite.checked` - `persona.memory.sleep.persisted` ## Development ```bash bun run test bun run check bun run build ``` The current test suite covers persona creation/loading, schedule generation/pruning, availability derivation, conversation context assembly, stale-draft rewrite checks, proactive conversation starts, and sleep-memory persistence.