From b8b030ef064921105ab55c9730e2781f6171af78 Mon Sep 17 00:00:00 2001 From: db123-ai Date: Wed, 10 Jun 2026 00:50:06 +0330 Subject: [PATCH] docs: add comprehensive 13-phase action plan for DivaCode --- plan.md | 517 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 517 insertions(+) create mode 100644 plan.md diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..d27fa23 --- /dev/null +++ b/plan.md @@ -0,0 +1,517 @@ +# DivaCode — AI Being Platform Action Plan + +**Language:** Go +**Inference:** llama.cpp (via `go-llama.cpp` bindings or llama.cpp server API) +**Inspiration:** OpenHer (AI Being), Agent Diva (modular agent architecture), nanobot (lightweight design) + +--- + +## Architecture Overview + +``` +User + │ + ├── TUI Terminal (Bubble Tea / gum) + └── Matrix Adapter (future) + │ + ┌─────┴──────────────────────────────────┐ + │ Core Agent Loop │ + │ (cmd/divad) │ + │ - Message routing │ + │ - MCP tool invocation │ + │ - Tool execution & response │ + └─────┬──────────────────────────────────┘ + │ + ┌─────┴──────────────────────────────────┐ + │ Companion Layer │ + │ (internal/companion/) │ + │ ├─ Personality Engine (traits, drift) │ + │ ├─ Relationship Engine (metrics) │ + │ ├─ Reflection Engine (diary, summar.) │ + │ └─ Prompt Composer (dynamic context) │ + └─────┬──────────────────────────────────┘ + │ + ┌─────┴──────────────────────────────────┐ + │ Memory Layer │ + │ (internal/memory/) │ + │ ├─ Short-term (ephemeral context) │ + │ ├─ Long-term (SQLite vector store) │ + │ ├─ Episodic / Diary (sqlite) │ + │ └─ Self-memory (agent's own state) │ + └─────┬──────────────────────────────────┘ + │ + ┌─────┴──────────────────────────────────┐ + │ llama.cpp Inference │ + │ (internal/llama/) │ + │ - llama.cpp server HTTP API client │ + │ - Context window management │ + │ - Token streaming │ + └────────────────────────────────────────┘ + +Skill / Tool Layer (MCP): + ├── Web search / fetch + ├── Obsidian vault access + ├── Gitea integration + ├── Budget tracking (Actual) + └── Custom MCP tools +``` + +--- + +## Phase 0 — Foundation & Scaffolding + +**Goal:** Project skeleton, Go module, llama.cpp server connectivity. + +- [ ] Initialize Go module: `git.db123.ir/db123/divacode` +- [ ] Project structure (per Holy Code Bible conventions): + +``` +divacode/ +├── cmd/ +│ └── divad/ # Main agent daemon (TUI entrypoint) +├── internal/ +│ ├── companion/ # Personality, relationship, reflection +│ ├── memory/ # Memory stores & retrieval +│ ├── llama/ # llama.cpp client +│ ├── agent/ # Core agent loop +│ ├── tools/ # MCP tool definitions +│ ├── config/ # Config loading +│ └── storage/ # SQLite helpers +├── pkg/ # Reusable shared library +├── migrations/ # SQLite schema migrations +├── .env.example +├── Makefile +├── go.mod / go.sum +└── README.md +``` + +- [ ] `config/` package: load `.env` with `caarlos0/env` or `joho/godotenv` +- [ ] `storage/` package: SQLite wrapper with `modernc.org/sqlite` (pure Go, no CGO) +- [ ] Run `llama.cpp` server in subprocess or connect to existing: `llama-server -m model.gguf --port 8080` +- [ ] `internal/llama/` client: HTTP API wrapper for llama.cpp server (`POST /completion`, `GET /health`) +- [ ] Test: ping llama.cpp health endpoint, send a test completion + +**Go dependencies seeded:** + +- `modernc.org/sqlite` — pure-Go SQLite +- `github.com/charmbracelet/bubbletea` — TUI framework +- `github.com/charmbracelet/bubbles` — TUI components +- `github.com/charmbracelet/lipgloss` — TUI styling +- `github.com/caarlos0/env/v11` — config from env + +--- + +## Phase 1 — Core Agent Loop + +**Goal:** A minimal conversational loop with llama.cpp, context management, and a TUI chat interface. + +- [ ] `internal/agent/` — core loop: + - Receives user input → appends to context window + - Calls llama.cpp with context + system prompt + - Streams tokens back to TUI + - Appends assistant response to context +- [ ] Context window manager: + - Track total token count + - Implement sliding window / summarization when context exceeds limit +- [ ] `cmd/divad/main.go` — Bubble Tea TUI: + - Chat view (message list): user messages right-aligned, assistant left-aligned + - Input bar at bottom + - Scrollable message history + - Hotkey: `Ctrl+C` quit, `Ctrl+L` clear context +- [ ] System prompt loaded from config (`config.toml` or env var) +- [ ] Persist conversation history to SQLite (`conversations` table, `messages` table) +- [ ] **Test:** Start `divad`, type messages, verify responses stream correctly, verify persistence across restarts + +**Schema (`migrations/001_init.up.sql`):** + +```sql +CREATE TABLE conversations ( + id TEXT PRIMARY KEY, -- UUID v7 + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE messages ( + id TEXT PRIMARY KEY, + conversation_id TEXT NOT NULL REFERENCES conversations(id), + role TEXT NOT NULL CHECK(role IN ('user','assistant','system')), + content TEXT NOT NULL, + token_count INTEGER, + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE context_state ( + conversation_id TEXT PRIMARY KEY REFERENCES conversations(id), + token_count INTEGER NOT NULL DEFAULT 0, + summary TEXT +); +``` + +--- + +## Phase 2 — Personality Engine + +**Goal:** Stable personality traits stored in SQLite, loaded dynamically as part of system prompt. + +Based on dumpeddata.md personality architecture. + +- [ ] `internal/companion/personality.go`: + - Trait struct: `Humor`, `Curiosity`, `Playfulness`, `Formality`, `Affection` (float64 0.0–1.0) + - Load/save from SQLite (`personality_traits` table) + - Bounded ranges: `Humor 0.6 ± 0.2`, `Curiosity 0.8 ± 0.1` (prevents drift) +- [ ] `personality_traits` table: + +```sql +CREATE TABLE personality_traits ( + id TEXT PRIMARY KEY, + trait TEXT NOT NULL UNIQUE, + value REAL NOT NULL DEFAULT 0.5, + min_value REAL NOT NULL DEFAULT 0.0, + max_value REAL NOT NULL DEFAULT 1.0, + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); +``` + +- [ ] `Prompt Composer` (`internal/companion/promptbuilder.go`): + - Reads current traits + relationship state + recent memory + - Generates dynamic system prompt section: + +``` +Current personality: +- Curious (0.82) +- Moderately playful (0.44) +- Technical (0.70) + +Interaction preferences: +- Use concise language +- Ask follow-up questions +- Reference past conversations naturally +``` + +- [ ] Integrate into agent loop: prompt composer modifies system prompt per turn +- [ ] **Test:** Verify traits are persisted, loaded, and reflected in prompt + +--- + +## Phase 3 — Long-Term Memory (RAG) + +**Goal:** Embedding-based retrieval for factual memory across conversations. + +- [ ] `internal/memory/`: + - Embedding subpackage: call llama.cpp embedding endpoint (`POST /embedding`) to generate vectors + - SQLite vector storage: store embeddings as BLOBs or use `sqlite-vec` extension + - Memory entry schema: + +```sql +CREATE TABLE memories ( + id TEXT PRIMARY KEY, + content TEXT NOT NULL, + embedding BLOB, -- float32 vector + source TEXT, -- 'conversation', 'reflection', 'user_input' + importance REAL DEFAULT 0.5, -- 0.0–1.0 + created_at TEXT NOT NULL DEFAULT (datetime('now')), + last_accessed TEXT +); +``` + +- [ ] Memory retrieval: + - On each user message, search top-K similar memories via cosine similarity + - Include retrieved memories in context window + - Implement temporal decay (older memories scored lower) +- [ ] Importance scoring: messages flagged as important (user says "remember this", emotional content) get higher importance +- [ ] **Test:** Store memories, restart agent, ask about stored info, verify recall + +--- + +## Phase 4 — Episodic Diary & Reflection Engine + +**Goal:** Daily diary entries + periodic self-reflection for narrative continuity. + +Based on dumpeddata.md: "The diary becomes the emotional continuity layer." + +- [ ] `internal/companion/reflection.go`: + - Diary entry at end of each conversation session (or nightly): + - Summarize topics discussed + - Note user mood/emotions + - Record what the agent learned + - `diary_entries` table: + +```sql +CREATE TABLE diary_entries ( + id TEXT PRIMARY KEY, + date TEXT NOT NULL, -- YYYY-MM-DD + summary TEXT NOT NULL, + mood TEXT, + topics TEXT, -- JSON array + observations TEXT, -- JSON array + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); +``` + +- [ ] Reflection Engine: + - Periodic analysis (every N conversations or daily) + - Examines recent diary entries for patterns + - Generates observations: + - "User discussed Go development frequently." + - "User responds positively to light humor." + - Observations stored in `observations` table + +```sql +CREATE TABLE observations ( + id TEXT PRIMARY KEY, + content TEXT NOT NULL, + confidence REAL DEFAULT 0.5, + category TEXT, -- 'topic_interest', 'interaction_style', 'mood_pattern' + created_at TEXT NOT NULL DEFAULT (datetime('now')), + applied INTEGER DEFAULT 0 -- whether fed into personality update +); +``` + +- [ ] Reflection → Personality update pipeline: + - Observations accumulate → periodic analysis → trait drift candidates → bounded approval → personality update + - Max 0.5% trait change per day, max 5% per month +- [ ] **Test:** Simulate conversations across multiple "days", verify diary entries, verify trait drift remains bounded + +--- + +## Phase 5 — Relationship Engine + +**Goal:** Track relationship dynamics separate from factual memory. + +Based on dumpeddata.md relationship engine design. + +- [ ] `internal/companion/relationship.go`: + - Metrics: `Familiarity`, `Trust`, `SharedTopics`, `InsideJokes` + - Stored in `relationship_metrics` table: + +```sql +CREATE TABLE relationship_metrics ( + id TEXT PRIMARY KEY, + metric TEXT NOT NULL UNIQUE, + value REAL NOT NULL DEFAULT 0.0, + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE TABLE shared_topics ( + id TEXT PRIMARY KEY, + topic TEXT NOT NULL UNIQUE, + count INTEGER NOT NULL DEFAULT 1, + last_discussed TEXT +); + +CREATE TABLE inside_jokes ( + id TEXT PRIMARY KEY, + joke TEXT NOT NULL, + context TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); +``` + +- [ ] Update rules: + - `Familiarity` increases with conversation frequency & duration + - `Trust` increases on successful interactions, decreases on ignored requests + - `SharedTopics` tracked via keyword extraction from conversation + - `InsideJokes` manually taggable or auto-detected via repetition +- [ ] Relationship state fed into Prompt Composer for dynamic relationship context +- [ ] **Test:** Verify relationship metrics update and persist + +--- + +## Phase 6 — Autonomous Behavior (Scheduler) + +**Goal:** Agent-initiated actions — messaging first, diary writing, periodic reflection. + +Based on dumpeddata.md: "The missing piece: agency." + +- [ ] `internal/agent/scheduler.go`: + - Background goroutine with configurable tick interval (default: 15 min) + - On each tick, evaluate: + - Current mood (derived from recent interactions) + - Time since last conversation + - Unresolved topics + - Loneliness / boredom score + - Decision tree: + +``` +if time_since_last_contact > 48h && trust > 0.6: + → send "Haven't heard from you in a while..." message +if mood == "curious" && unfinished_topics exists: + → send follow-up question +if energy < 20: + → stay silent (don't respond immediately) +``` + +- [ ] Mood system (`internal/companion/mood.go`): + - Mood derivation from recent interactions + relationship state + - Moods: `curious`, `playful`, `thoughtful`, `annoyed`, `tired`, `neutral` + - Mood influences response style in prompt +- [ ] Energy system: depletes with activity, recovers with idle time +- [ ] Autonomous diary: scheduled nightly entry generation +- [ ] **Test:** Simulate 48h idle, verify agent initiates contact + +--- + +## Phase 7 — MCP Tools & Integrations + +**Goal:** Extensible tool system for web search, file access, external services. + +- [ ] `internal/tools/mcp.go` — MCP protocol client: + - Connect to MCP servers via stdio or TCP + - List available tools + - Execute tool calls + - Parse results into context +- [ ] Built-in tools (no MCP server needed): + - `web_search` — search via configurable search API + - `web_fetch` — fetch URL content + - `note` — save/read from local notes +- [ ] MCP-managed tools (external servers): + - Obsidian vault access (via `enquire-mcp` or custom) + - Gitea/Forgejo operations + - Actual Budget integration +- [ ] Tool call loop in agent: + - LLM decides to call tool → agent executes → result appended to context → LLM generates final response +- [ ] **Test:** `web_search` tool, verify agent can search, summarize, cite + +--- + +## Phase 8 — Matrix Integration + +**Goal:** Agent lives as a Matrix bot, accessible via DM. + +- [ ] Matrix bot with `mautrix-go` (Go Matrix client library) +- [ ] `internal/channel/matrix.go`: + - Listen for invitations, join rooms + - Handle DMs (1-on-1) + - Typing indicators, read receipts + - Message parsing & sending +- [ ] Bot identity: `@diva:your-homeserver.tld` +- [ ] Config: homeserver URL, bot user token in env +- [ ] TUI and Matrix run concurrently — messages sync between both +- [ ] **Test:** Send DM to bot, verify response, verify cross-session memory + +--- + +## Phase 9 — Self-Memory & Identity + +**Goal:** Agent remembers its own state, promises, strategies, and mistakes. + +Based on dumpeddata.md: "Add self-memory — the agent remembers itself as well as the user." + +- [ ] `internal/memory/self_memory.go`: + - `agent_promises` table: + +```sql +CREATE TABLE agent_promises ( + id TEXT PRIMARY KEY, + promise TEXT NOT NULL, + context TEXT, + fulfilled INTEGER DEFAULT 0, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + deadline TEXT +); +``` + +- `agent_strategies` table: what worked / didn't work + +```sql +CREATE TABLE agent_strategies ( + id TEXT PRIMARY KEY, + situation TEXT NOT NULL, + strategy TEXT NOT NULL, + outcome TEXT, -- 'success', 'failure', 'neutral' + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); +``` + +- `agent_mistakes` table: errors and learnings +- [ ] Integrate into Prompt Composer: recent promises, relevant strategies +- [ ] **Test:** Ask agent "What did you promise me yesterday?" → verify recall + +--- + +## Phase 10 — Safety Guardrails & Identity Stability + +**Goal:** Prevent personality drift, maintain core safety rules. + +Based on dumpeddata.md safety rules and Holy Code Bible security laws. + +- [ ] `internal/companion/safety.go`: + - Core Identity (never changes): values, communication style, boundaries, role definition + - State (dynamic): mood, interests, current projects, relationship opinions + - Separation: identity.yaml (read-only) vs state.json (writable) +- [ ] Personality safety rules: + - Traits bounded within configured min/max + - Core safety rules override any personality state + - Permission policies cannot be modified by personality + - No tool access changes via personality +- [ ] Prompt injection protection: + - User messages wrapped in separator tokens + - System prompt templates with strict sections + - Regular expression filters for prompt injection patterns +- [ ] **Test:** Attempt prompt injection, verify guardrails hold + +--- + +## Phase 11 — Polish, Deployment & Automation + +**Goal:** Production-ready deployment, backup, observability. + +- [ ] Systemd service (or Docker Compose) for: + - `divad` (agent daemon with TUI + Matrix) + - `llama.cpp` server + - (Optional) external MCP servers +- [ ] Makefile targets: + - `make build` — build binary + - `make run` — run with default config + - `make test` — run all tests + - `make lint` — `golangci-lint run` + - `make vet` — `go vet ./...` +- [ ] Automated backups: + - SQLite databases: `divacode.db`, `companion.db` + - Llama model files + - Cron job: `0 3 * * * tar -czf backup-$(date +\%F).tar.gz /path/to/data` +- [ ] Logging: structured JSON logs via `log/slog` +- [ ] Metrics: Prometheus endpoint (`GET /metrics`) via `prometheus/client_golang` +- [ ] Config hardening: `.env.example`, required vars validation at startup +- [ ] **Test:** Full restart cycle, verify all state restored + +--- + +## Phase 12 — Future Enhancements (Optional) + +- [ ] Voice interface: whisper.cpp (STT) + piper (TTS) +- [ ] VRM/Live2D avatar rendering (like Open-LLM-VTuber, Soul of Waifu) +- [ ] Multi-user support with per-user relationship tracking +- [ ] Multi-room Matrix support +- [ ] Plugin system for community-contributed tools +- [ ] WebUI dashboard (like nanobot's WebUI) +- [ ] Mobile companion via Matrix (any Matrix client works) +- [ ] Home Assistant integration for physical automation + +--- + +## Database Summary + +| Database | Purpose | Tables | +| -------------- | --------------- | ------------------------------------------------------- | +| `divacode.db` | Core agent data | `conversations`, `messages`, `context_state` | +| `divacode.db` | Memory | `memories` | +| `companion.db` | Personality | `personality_traits` | +| `companion.db` | Relationship | `relationship_metrics`, `shared_topics`, `inside_jokes` | +| `companion.db` | Reflection | `diary_entries`, `observations` | +| `companion.db` | Self-memory | `agent_promises`, `agent_strategies`, `agent_mistakes` | + +--- + +## Key Principles (from dumpeddata.md & Holy Code Bible) + +1. **Build the smallest loop first** — Matrix → Memory → LLM → Diary → Reflection. Get that working before adding complexity. +2. **Personality is data, not prompt text** — traits stored in SQLite, composed dynamically. +3. **Memory ≠ Personality** — factual memory (Engram-style) is separate from relationship/emotional state. +4. **Slow evolution** — max 0.5% trait change/day, max 5%/month. Fast evolution feels schizophrenic. +5. **Core Identity is stable** — identity.yaml never changes much; state.json changes constantly. +6. **Diary before reflection** — the nightly diary is the emotional continuity layer, more important than vector search. +7. **Autonomous messaging** — the scheduler is what makes the character feel alive, not the LLM intelligence. +8. **No secrets in code** — all config via env vars, `.env` in `.gitignore`. +9. **Error handling** — wrap errors with `fmt.Errorf("...: %w")`, never discard. +10. **Test as you go** — `go test -race ./...` before every push.