docs: add BoxBrain foundation plan
This commit is contained in:
217
docs/plans/2026-05-11-boxbrain-foundation.md
Normal file
217
docs/plans/2026-05-11-boxbrain-foundation.md
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
# BoxBrain Foundation Implementation Plan
|
||||||
|
|
||||||
|
> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.
|
||||||
|
|
||||||
|
**Goal:** Build BoxBrain as a TypeScript/Bun framework for creating and operating IdentityDB-backed synthetic personas that feel like real people in DM-style conversations.
|
||||||
|
|
||||||
|
**Architecture:** BoxBrain is a library-first framework with optional API/server adapters later. The core exposes typed services for persona initialization, schedule generation, availability status, inbound conversation turns, and proactive outbound messages. Each persona maps to exactly one IdentityDB space, and all generated biographies, schedules, conversations, statuses, and relationship memories are stored as facts in that space.
|
||||||
|
|
||||||
|
**Tech Stack:** Bun, TypeScript, Vitest, tsup, IdentityDB, provider-agnostic LLM/image adapters, deterministic test doubles.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Product scope
|
||||||
|
|
||||||
|
BoxBrain models one persona as a durable memory space plus a runtime harness:
|
||||||
|
|
||||||
|
- `initializePersona(input)` creates a persona, asks an LLM adapter to generate a detailed life story from personality/history/values/likes/dislikes/relationships, asks another extraction path to split that story into IdentityDB facts, stores every fact in the persona's IdentityDB space, and optionally generates a profile image.
|
||||||
|
- `generateSchedule(input)` creates a month/week/day schedule for a persona around a date, stores schedule facts keyed by time topics, and derives contact availability windows from the schedule.
|
||||||
|
- `setAvailability(input)` explicitly sets or updates contact availability: `online`, `do_not_disturb`, or `offline`.
|
||||||
|
- `sendMessage(input)` handles a user text turn by loading mandatory memories, delegating contextual memory search to an LLM, then asking the persona LLM to emit one or more short DM messages through a tool-like output contract.
|
||||||
|
- `proactivelyMessage(input)` has no user text and asks the persona to initiate a natural DM.
|
||||||
|
- Runtime delivery applies non-LLM typing delays based on character count: random 0.05–0.08 seconds per character.
|
||||||
|
|
||||||
|
## Design decisions
|
||||||
|
|
||||||
|
1. **Library-first API**
|
||||||
|
- Implement services and typed interfaces before HTTP routing.
|
||||||
|
- A later REST/RPC adapter can wrap the same core methods without duplicating logic.
|
||||||
|
|
||||||
|
2. **Adapter-first AI provider selection**
|
||||||
|
- Define small interfaces instead of coupling to a provider SDK:
|
||||||
|
- `TextModelAdapter.generateText(request)`
|
||||||
|
- `StructuredModelAdapter.generateObject(request)`
|
||||||
|
- `ImageModelAdapter.generateImage(request)`
|
||||||
|
- Provide deterministic fake adapters in tests.
|
||||||
|
- Provider/model choice is passed via adapter instances, making BoxBrain easier to configure than IdentityDB's lower-level LLM bridge.
|
||||||
|
|
||||||
|
3. **IdentityDB space per persona**
|
||||||
|
- `persona.spaceName` is the canonical scope for all facts.
|
||||||
|
- No cross-persona reads unless explicitly requested by future APIs.
|
||||||
|
- Facts use metadata to identify domains: `persona.biography`, `persona.schedule`, `persona.availability`, `persona.conversation`, `persona.relationship`.
|
||||||
|
|
||||||
|
4. **LLM delegation boundaries**
|
||||||
|
- Biography generation is one structured LLM call.
|
||||||
|
- Fact splitting is one structured LLM call that produces `BoxBrainFactDraft[]`.
|
||||||
|
- Mandatory memory retrieval is deterministic.
|
||||||
|
- Natural contextual memory extraction is delegated to a retrieval-planner LLM.
|
||||||
|
- Persona response generation is delegated to a persona LLM with a tool-output schema for short messages and optional state-change request.
|
||||||
|
|
||||||
|
5. **Human-feeling messages**
|
||||||
|
- Persona messages are short, usually one sentence or less.
|
||||||
|
- A turn can produce multiple messages.
|
||||||
|
- The response planner may intentionally omit spaces or introduce typo-like text when persona style supports it.
|
||||||
|
- Timing is deterministic in tests through an injectable RNG.
|
||||||
|
|
||||||
|
6. **Availability semantics**
|
||||||
|
- `offline`: no answer until a blocker event ends.
|
||||||
|
- `do_not_disturb`: first answer has low immediate-reply probability plus possible random delay; later messages in the same active exchange only use typing delay.
|
||||||
|
- `online`: first answer always occurs, with a short-to-somewhat-long random initial delay; later messages only use typing delay.
|
||||||
|
- A persona may refuse or wind down a conversation before changing availability, using 1–3 short goodbye messages, then a tool-style status update.
|
||||||
|
|
||||||
|
## Task 1: Bootstrap package metadata and strict TypeScript
|
||||||
|
|
||||||
|
**Objective:** Create a Bun/TypeScript package foundation without production behavior.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `package.json`
|
||||||
|
- Create: `tsconfig.json`
|
||||||
|
- Create: `tsup.config.ts`
|
||||||
|
- Create: `vitest.config.ts`
|
||||||
|
- Create: `.gitignore`
|
||||||
|
- Modify: `README.md`
|
||||||
|
|
||||||
|
**Steps:**
|
||||||
|
1. Add package scripts: `test`, `check`, `build`, `clean`.
|
||||||
|
2. Add dependencies: `identitydb` via local `file:../IdentityDB` for initial development.
|
||||||
|
3. Add dev dependencies: `typescript`, `vitest`, `tsup`, `@types/node`.
|
||||||
|
4. Configure strict TypeScript with `exactOptionalPropertyTypes`.
|
||||||
|
5. Keep README in English with a concise project description.
|
||||||
|
6. Run `bun install`, `bun run check`, `bun run test`.
|
||||||
|
7. Commit: `chore: bootstrap BoxBrain package`.
|
||||||
|
|
||||||
|
## Task 2: Define public domain and adapter contracts with TDD
|
||||||
|
|
||||||
|
**Objective:** Establish stable typed contracts for personas, adapters, facts, schedules, availability, and messages.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/types.ts`
|
||||||
|
- Create: `src/adapters.ts`
|
||||||
|
- Create: `src/index.ts`
|
||||||
|
- Test: `tests/public-api.test.ts`
|
||||||
|
|
||||||
|
**Behavior to test first:**
|
||||||
|
- Public exports include all adapter interfaces and domain types.
|
||||||
|
- `createTypingDelay` computes per-message timing inside the configured character range when using deterministic RNG.
|
||||||
|
|
||||||
|
**Implementation notes:**
|
||||||
|
- Use type-only tests sparingly; prefer runtime helper tests where possible.
|
||||||
|
- Keep provider adapters minimal and provider-agnostic.
|
||||||
|
|
||||||
|
**Commit:** `feat: define BoxBrain public contracts`.
|
||||||
|
|
||||||
|
## Task 3: Implement deterministic timing utilities with TDD
|
||||||
|
|
||||||
|
**Objective:** Provide reusable timing calculations for online/DND first replies and per-message typing delay.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/timing.ts`
|
||||||
|
- Test: `tests/timing.test.ts`
|
||||||
|
|
||||||
|
**Behavior to test first:**
|
||||||
|
- Typing delay equals `message.length * randomSecondsPerCharacter` with random range 0.05–0.08 by default.
|
||||||
|
- Empty messages produce zero typing delay.
|
||||||
|
- First reply timing distinguishes online and do-not-disturb.
|
||||||
|
- Subsequent replies skip initial availability delay.
|
||||||
|
|
||||||
|
**Commit:** `feat: add human typing timing utilities`.
|
||||||
|
|
||||||
|
## Task 4: Implement IdentityDB fact persistence helpers with TDD
|
||||||
|
|
||||||
|
**Objective:** Convert BoxBrain fact drafts into IdentityDB writes scoped to one persona space.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/memory.ts`
|
||||||
|
- Test: `tests/memory.test.ts`
|
||||||
|
|
||||||
|
**Behavior to test first:**
|
||||||
|
- Facts are stored with the provided `spaceName`.
|
||||||
|
- Fact metadata includes a BoxBrain domain and source marker.
|
||||||
|
- Empty fact arrays are accepted without writes.
|
||||||
|
|
||||||
|
**Implementation notes:**
|
||||||
|
- Use IdentityDB's `addFact` and `upsertSpace` APIs.
|
||||||
|
- Prefer integration tests with SQLite `:memory:`.
|
||||||
|
|
||||||
|
**Commit:** `feat: persist BoxBrain facts in persona spaces`.
|
||||||
|
|
||||||
|
## Task 5: Implement persona initialization with TDD
|
||||||
|
|
||||||
|
**Objective:** Create personas, generate biographies, split them into facts, store them in IdentityDB, and optionally generate profile images.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/persona.ts`
|
||||||
|
- Test: `tests/persona.test.ts`
|
||||||
|
|
||||||
|
**Behavior to test first:**
|
||||||
|
- Initialization creates a stable persona object with `id`, `spaceName`, and profile fields.
|
||||||
|
- Biography adapter is called with personality, history, values, preferences, relationships, and current date context.
|
||||||
|
- Fact splitter adapter output is stored in the persona's space.
|
||||||
|
- Profile image adapter is not called unless requested.
|
||||||
|
- Profile image result is returned and stored as a fact when requested.
|
||||||
|
|
||||||
|
**Commit:** `feat: initialize IdentityDB-backed personas`.
|
||||||
|
|
||||||
|
## Task 6: Implement schedule and availability APIs with TDD
|
||||||
|
|
||||||
|
**Objective:** Generate schedules around dates, persist them as time-topic facts, and derive contact availability.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/schedule.ts`
|
||||||
|
- Create: `src/availability.ts`
|
||||||
|
- Test: `tests/schedule.test.ts`
|
||||||
|
- Test: `tests/availability.test.ts`
|
||||||
|
|
||||||
|
**Behavior to test first:**
|
||||||
|
- Day/week/month schedule requests call the schedule LLM adapter with the right horizon.
|
||||||
|
- Generated schedule items are stored with time topics and schedule metadata.
|
||||||
|
- Online/DND/offline states are derived from schedule contactability.
|
||||||
|
- Deleting schedules can remove by elapsed event or before a cutoff date once IdentityDB supports deletion/query hooks; until then expose a plan-safe no-op interface with documented limitation.
|
||||||
|
|
||||||
|
**Commit:** `feat: add schedule and availability APIs`.
|
||||||
|
|
||||||
|
## Task 7: Implement conversation harness with TDD
|
||||||
|
|
||||||
|
**Objective:** Handle inbound text and proactive messages using mandatory memory loading, LLM-guided retrieval, persona response planning, typing delays, and optional status-change tools.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/conversation.ts`
|
||||||
|
- Test: `tests/conversation.test.ts`
|
||||||
|
|
||||||
|
**Behavior to test first:**
|
||||||
|
- Inbound conversation loads mandatory memory categories before contextual retrieval.
|
||||||
|
- Retrieval planner receives the user text and mandatory memory summary.
|
||||||
|
- Persona response planner emits one or more short messages.
|
||||||
|
- Each message receives a typing delay from `createTypingDelay`.
|
||||||
|
- Offline status blocks response.
|
||||||
|
- DND first replies can be delayed or skipped based on injected RNG.
|
||||||
|
- Proactive messages work without a user text parameter.
|
||||||
|
- Status-change tool output is translated into an availability update after optional goodbye messages.
|
||||||
|
|
||||||
|
**Commit:** `feat: add DM-style conversation harness`.
|
||||||
|
|
||||||
|
## Task 8: Documentation and examples
|
||||||
|
|
||||||
|
**Objective:** Document framework usage and provide a runnable example using fake adapters.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `README.md`
|
||||||
|
- Create: `examples/basic.ts`
|
||||||
|
|
||||||
|
**Verification:**
|
||||||
|
- `bun run test`
|
||||||
|
- `bun run check`
|
||||||
|
- `bun run build`
|
||||||
|
|
||||||
|
**Commit:** `docs: document BoxBrain foundation usage`.
|
||||||
|
|
||||||
|
## Initial MVP cut for this session
|
||||||
|
|
||||||
|
Start with Tasks 1–4 so the repository has a tested foundation:
|
||||||
|
|
||||||
|
1. Package/bootstrap files.
|
||||||
|
2. Public contracts.
|
||||||
|
3. Timing utilities.
|
||||||
|
4. IdentityDB fact persistence helpers.
|
||||||
|
|
||||||
|
The persona, schedule, availability, and conversation services should be implemented after the foundation is green.
|
||||||
Reference in New Issue
Block a user