# @ai Project Management ## Why @ai Exists Every AI-enabled application in this ecosystem independently re-implemented (or skipped) the same four concerns: identity, memory, personality, and context assembly. @chobit had `miku.json` and a 10-message ephemeral history. @life had `memory.service.ts` siloed per-platform, inline agent personas, and its own ambient companion service (AmbientCompanionService). @kthulu had no persistent memory or identity at all. Each app assembled LLM prompts differently with no shared contract. @ai consolidates those four concerns into a single runtime. It is the *mind* of the assistant. Applications are the *body* (@chobit), *hands* (@kthulu), and *world* (@life, @education, @career). ## What @ai Replaces | What's being removed | Where it lived | Replaced by | |----------------------|---------------|-------------| | `@life/life-ai` companion service | `@life/@applications/ai/services/companion/` | @ai identity + nag + context | | `@life/platform-ai` service | `@life/@applications/ai/services/platform-ai/` | @ai identity + nag + context | | `AmbientCompanionService` | `@life/messenger/notifications/backend/` | @ai M4 nag module | | `NudgeService` | `@life/messenger/notifications/backend/` | @ai M4 nag module | | `memory.service.ts` | `@life/platform-ai/features/assistant/` | @ai M2 memory module | | `miku.json` (local) | `@chobit/config/personalities/` | @ai M3 personality module | | `.quinn` CronCreate nag | `~/.claude/commands/nag-start.md` | @ai M4 `POST /nag/start` | ## Correct Location **Current:** `~/Code/@applications/@ai/` (wrong tier — placed in infrastructure layer) **Correct:** `~/Code/@projects/@ai/` (a domain project, like @life and @kthulu) When M0 scaffold begins, create at `@projects/@ai/`, not `@applications/@ai/`. Exported packages go in `@projects/@ai/@packages/` (not global `~/Code/@packages/`). ## Directory Structure ``` .project/ ├── README.md # This file ├── streams/ # Active feature workstreams │ └── / │ ├── README.md # Feature overview and architecture │ ├── STATUS.md # Current progress and blockers │ ├── HANDOFF.md # Session handoff context │ └── NOTES.md # Technical decisions and learnings ├── history/ # Completed work records │ └── YYYYMMDD_description.md └── templates/ # Stream templates ``` ## Active Streams None — project not yet scaffolded. ## Milestone Roadmap ### M0: Project Scaffold 🔲 - `@applications/@ai/` directory + `app.manifest.yaml` - `services/ai-core/` — NestJS app via `@lilith/service-nestjs-bootstrap` - Docker compose: PostgreSQL (26395) + Redis (26394) - `GET /health` endpoint - `./run` task runner (dev/stop/status/logs) - `packages/ai-client/` skeleton (`@lilith/ai-client`) ### M1: Identity Module 🔲 - `PersonaEntity` — id, name, voice_id, tags, description (maps from miku.json) - `UserIdentityEntity` — id, display_name, bound_persona_id, metadata JSONB - CRUD endpoints: `GET/POST/PATCH /identity`, `GET/POST /identity/:id/personas` - Seed: "quinn" identity + "miku" persona from existing `godot-desktop/config/personalities/miku.json` - Client: `ai-client/identity.ts` ### M2: Memory Module 🔲 - `MemoryEntryEntity` — key, content, category, tags[], metadata JSONB, soft-delete (pattern from `@life/platform-ai/features/assistant/generic-tools/services/memory.service.ts`) - Redis cache layer with PG fallback (pattern from `@ml/knowledge-platform/features/api/service/src/cache/subject-cache.ts`) - Endpoints: `GET/POST/PATCH/DELETE /memory`, `GET /memory/search?q=&tags=&category=` - TTL-based cache with subject invalidation - Client: `ai-client/memory.ts` ### M3: Personality Module 🔲 - Personality template loader — reads JSON files from `config/personalities/` - Prompt composer — assembles system prompt from template + context payload (ports the logic from `@chobit/godot-desktop/platform/conversation/prompt_composer.gd`) - Composition order: identity → voice_constraint → traits → negatives → emotion_tags → depth_tier → context_modifiers → situation_overrides - Endpoints: - `GET /personality` — list available personalities - `GET /personality/:id` — personality definition - `POST /personality/:id/compose` — compose system prompt from context payload - Migrate `miku.json` from `@chobit` to `@ai` as the source of truth - Client: `ai-client/personality.ts` ### M4: Tasks Module 🔲 - `TaskListEntity` — id, name, identity_id, description, metadata JSONB - `TaskEntity` — id, list_id, content, priority (0–100), status, due_at, tags[], metadata JSONB - status: `pending | in_progress | done | snoozed` - Redis pub/sub via `@lilith/eventbus` — emit `ai.task.created`, `ai.task.updated`, `ai.task.completed` - Endpoints: - `GET/POST /tasks` — list management - `GET/POST /tasks/:list_id/items` — task CRUD - `PATCH /tasks/:list_id/items/:id` — update status/priority - Seed: "quinn-platforms" task list from `.quinn/business/registrations.md` - Client: `ai-client/tasks.ts` **Full stream spec:** `.project/streams/m4-nag-loop/README.md` Two working reference implementations inform M4's design: - **`.quinn` nag loop** — file-based context, Miku TTS, CronCreate (simple, working today) - **`@life` ambient companion** — API-based context, iMessage, NudgeSession entity (sophisticated, production) M4 generalizes both into a unified nag engine with `ContextProvider` + `DeliveryChannel` interfaces, `NagLoopEntity` + `NagSessionEntity` persistence, and `POST/DELETE/GET /nag/*` endpoints. ### M5: Context Module 🔲 The primary integration endpoint — assembles everything into a ready-to-use LLM payload. - `POST /context/compose` — accepts identity_id, personality_id, recent_messages[], context{} - Assembly pipeline: 1. Load identity → user binding 2. Compose personality system prompt (→ M3 endpoint) 3. Query memory for relevant entries (semantic search on recent_messages) 4. Fetch active tasks for identity → optional task_summary string 5. Return: `{ system_prompt, memory_injections[], task_summary }` - Replaces: `@chobit` direct model-boss calls, `@life` memory.service.ts inline assembly - Client: `ai-client/context.ts` ### M5b: Response Format Module 🔲 Decides model selection and dual-response config per-request. - `ResponseFormat` returned alongside `system_prompt` from `/context/compose` - Model selection logic: conversation → `qwen3-4b`, complex → `qwen3-32b`, TTS always → `qwen3-4b` - Dual-response modes: `text_only | tts_only | dual` - Depth tier → TTS max_tokens mapping (from personality module) - Consumer capability registration: declare `tts_capable: true/false` on identity - `tts` config includes: model, max_tokens, voice_id, personality_id - Injected TTS system constraint: "Respond in 1–3 short spoken sentences. No lists, no markdown." - When to speak: companions (dual), nag loop (tts_only), API (text_only), notifications (tts_only) ### M6: ai-client Package 🔲 - Publish `@lilith/ai-client` to Verdaccio (npm.nasty.sh:4873) - Full TypeScript client covering all 5 modules - React hooks: `useMemory()`, `useTasks()`, `usePersonality()` - Auto-retry + error handling - Use `npx @lilith/dev-publish` for fast iteration ### M7: @chobit Integration 🔲 Wire @chobit to use @ai: - `llm_client.gd` → HTTP `POST /context/compose` (replaces raw model-boss endpoint) - `conversation_store.gd` → async sync to `POST /memory` after each turn - Remove `MAX_HISTORY = 10` cap — full history lives in @ai - `prompt_composer.gd` → becomes thin HTTP client to `POST /personality/miku/compose` - Extend Redis eventbus namespace: `chobit.task.*` events from @ai ### M8: Relationship Module 🔲 Dynamic personality — relationship arc, trait intensity, shared history injection. - `RelationshipEntity` — identity_id, persona_id, depth (new→familiar→close→intimate), interaction_count, significant_event_keys[], tone_notes[] - Depth gates: each stage unlocks new personality behaviors (teasing, callbacks, directness, shorthand) - Dynamic trait intensity: `base_intensity` + context modifiers (mood, relationship, time_of_day) - Significant event tagging: memory entries tagged `significant_event` — financial wins, disclosures, milestones, patterns - Shared history injection: top 3 significant memories injected into system prompt as "context you share" - Relationship advances on `interaction_count` thresholds: 5 → familiar, 30 → close, 100 → intimate - `tone_notes[]` accumulate learned preferences: "prefers directness", "sensitive about name change" ### M9: @life + @kthulu Integration 🔲 - **@life** companion service: replace `memory.service.ts` with `@lilith/ai-client` calls - **@kthulu** context-builder: add identity layer — `@ai /context/compose` wraps code context - Both consume same `@lilith/ai-client` package --- ## Key Technical Decisions | Decision | Choice | Rationale | |----------|--------|-----------| | Separate from @ml | Yes | @ml = inference/training/RAG; @ai = identity/memory/personality/tasks | | Memory storage | Redis (short-term) + PostgreSQL (long-term) | Inherit @life pattern — proven in production | | Session management | `@lilith/ml-session-manager` | Already exists, pluggable store interface | | Personality format | JSON templates (inherit miku.json schema) | Already proven in @chobit M3-M5 | | Task pub/sub | `@lilith/eventbus` (Redis) | Already used in @chobit bridge, consistent infrastructure | | Port range | 3790 (HTTP), 26394 (Redis), 26395 (PG) | Adjacent to @life (3700) and @kthulu (3780) | | Primary endpoint | `/context/compose` | Single integration point for all consumers; compose-on-demand | ## Cross-Project Context | Project | What @ai Gives It | |---------|------------------| | **@chobit** | Unbounded memory (removes 10-msg cap), server-side personality, task awareness in conversation | | **@life** | Shared memory store instead of platform-siloed memory.service.ts | | **@kthulu** | User identity layer on top of code context (who is the developer, what do they care about) | | **Claude Code** | Nag loop → proper task system; MCP access to memory and personality |