Skip to content

Commit 448b535

Browse files
yhbcode000claude
andcommitted
Add welcome screen, setup wizard, auto-naming, and emoji UX
- Enable Redis AOF persistence (~/.multiverse_note/data/) for session resume - Add SetupScreen: validates API keys on launch, saves to ~/.multiverse_note/.env - Add WelcomeScreen: New Session, Resume Session, About, Exit with keybindings - Add NamingNode: auto-generates branch names and tags via gpt-4o-mini - Add slash commands: /rename, /tag, /help - Remove mandatory tag popup after each LLM response - Add BranchStore.rename() and rich branch tree (turn count, tags, brief) - Add system message role with muted/italic styling - Add emoji throughout UI (🌿 branches, 👤/🤖 labels, 💬 input, 🌌 title) - Wire NamingNode as third daemon process gated on cfg.llm.naming.enabled - Add naming config section to all LLM yaml configs - Add 6 new NamingNode tests (57 total, all passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 71e78e2 commit 448b535

60 files changed

Lines changed: 6854 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# LLM API Keys (set the one matching your configured provider)
2+
OPENAI_API_KEY=sk-your-openai-api-key-here
3+
4+
# Redis (optional — defaults match conf/redis/default.yaml)
5+
# REDIS_HOST=localhost
6+
# REDIS_PORT=6379
7+
# REDIS_DB=0
8+
# REDIS_PASSWORD=

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,7 @@ cython_debug/
205205
marimo/_static/
206206
marimo/_lsp/
207207
__marimo__/
208+
209+
# MultiverseNote
210+
logs/
211+
outputs/

README.md

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
# MultiverseNote v2
2+
3+
## Introduction
4+
5+
MultiverseNote is an open-source terminal-based application that transforms AI chatbot interactions into structured knowledge management workflows. It introduces a **branch management system** where users can discuss topics on a main branch and create new branches for in-depth exploration, enabling systematic and continuous knowledge development.
6+
7+
Each conversation is organized into **branches** with numbered references (e.g. `#1`, `#2`), allowing you to fork discussions, load context from other branches, and tag conversation pairs for easy retrieval.
8+
9+
### Core Architecture
10+
11+
Every component (UI, LLM, context management) runs as an **isolated process node**, communicating exclusively through **Redis Pub/Sub**. This ensures modularity and allows components to be developed, tested, and scaled independently.
12+
13+
```mermaid
14+
flowchart LR
15+
UI["Terminal UI\n(Textual)"]
16+
CTX["ContextNode\n(Branch & Context)"]
17+
LLM["LLMNode\n(litellm)"]
18+
R[(Redis)]
19+
20+
UI -- "ch:user_input" --> R
21+
R -- "ch:user_input" --> CTX
22+
CTX -- "store user node\n+ assemble context" --> R
23+
CTX -- "ch:llm_request" --> R
24+
R -- "ch:llm_request" --> LLM
25+
LLM -- "ch:llm_response" --> R
26+
R -- "ch:llm_response" --> UI
27+
28+
style R fill:#dc382c,color:#fff
29+
style UI fill:#1a8cff,color:#fff
30+
style CTX fill:#2b8a3e,color:#fff
31+
style LLM fill:#7c3aed,color:#fff
32+
```
33+
34+
---
35+
36+
## Features
37+
38+
```mermaid
39+
gitGraph
40+
commit id: "user: What is Rust?"
41+
commit id: "assistant: Rust is a..."
42+
branch deep-dive
43+
commit id: "user: Explain ownership"
44+
commit id: "assistant: Ownership in Rust..."
45+
branch ownership-examples
46+
commit id: "user: Show me borrowing"
47+
commit id: "assistant: Here is an example..."
48+
checkout deep-dive
49+
commit id: "user: What about lifetimes?"
50+
commit id: "assistant: Lifetimes ensure..."
51+
checkout main
52+
commit id: "user: Compare Rust vs Go"
53+
commit id: "assistant: Both are systems..."
54+
```
55+
56+
- **Branch Management** — Create, switch, and navigate conversation branches with parent-child relationships
57+
- **Context References** — New branches can reference existing branches, loading their conversation history as context for the LLM
58+
- **Tag System** — Tag conversation pairs with colored labels for organization and retrieval
59+
- **Multi-Provider LLM** — Supports OpenAI, Anthropic, and local models via litellm
60+
- **Terminal UI** — Full keyboard-navigable TUI built with Textual
61+
- **Isolated Nodes** — Each component runs as a separate process communicating via Redis
62+
- **File-based Logging** — All logs written to rotating files, no terminal output clutter
63+
64+
---
65+
66+
## Prerequisites
67+
68+
- **Python** >= 3.11
69+
- **Redis** server running locally (default: `localhost:6379`)
70+
- **uv** package manager
71+
- An **LLM API key** (e.g. `OPENAI_API_KEY` for the default OpenAI provider)
72+
73+
---
74+
75+
## Installation
76+
77+
```bash
78+
# Clone the repository
79+
git clone https://github.com/AhmadCodes/MultiverseNoteV2.git
80+
cd MultiverseNoteV2
81+
82+
# Install dependencies
83+
uv sync
84+
```
85+
86+
---
87+
88+
## Usage
89+
90+
### Start Redis
91+
92+
```bash
93+
redis-server
94+
```
95+
96+
### Set your API key
97+
98+
```bash
99+
export OPENAI_API_KEY="sk-..."
100+
```
101+
102+
### Launch the application
103+
104+
```bash
105+
uv run multiverse
106+
```
107+
108+
### Keyboard Shortcuts
109+
110+
| Key | Action |
111+
|-----|--------|
112+
| `Enter` | Send message |
113+
| `Ctrl+B` | Open branch tree |
114+
| `Ctrl+Q` | Quit |
115+
| `Escape` | Close modal / Go back |
116+
| `N` | New branch (in branch tree) |
117+
118+
---
119+
120+
## Configuration
121+
122+
Configuration is managed via [Hydra](https://hydra.cc/) with composable YAML files in `src/multiverse_note/conf/`.
123+
124+
### LLM Provider
125+
126+
Default is OpenAI. To use Anthropic:
127+
128+
```bash
129+
uv run multiverse llm=anthropic
130+
```
131+
132+
Or override individual settings:
133+
134+
```bash
135+
uv run multiverse llm.model=openai/gpt-4o-mini llm.temperature=0.5
136+
```
137+
138+
### Redis
139+
140+
```bash
141+
uv run multiverse redis.host=myhost redis.port=6380 redis.db=1
142+
```
143+
144+
### Config Files
145+
146+
```
147+
src/multiverse_note/conf/
148+
├── config.yaml # Main config (composes all groups)
149+
├── redis/default.yaml # host, port, db, password
150+
├── llm/
151+
│ ├── default.yaml # Default provider (OpenAI)
152+
│ ├── openai.yaml
153+
│ └── anthropic.yaml
154+
├── ui/default.yaml # Theme, layout preferences
155+
└── logging/default.yaml # Log level, file path, rotation
156+
```
157+
158+
---
159+
160+
## Process Model
161+
162+
```mermaid
163+
flowchart TB
164+
MAIN["main.py\n@hydra.main"]
165+
166+
MAIN -->|"multiprocessing.Process\n(daemon)"| CTX_PROC["ContextNode Process"]
167+
MAIN -->|"multiprocessing.Process\n(daemon)"| LLM_PROC["LLMNode Process"]
168+
MAIN -->|"runs in main process\n(needs terminal)"| UI_PROC["MultiverseApp (Textual)"]
169+
170+
CTX_PROC -. "Redis Pub/Sub" .- REDIS[(Redis)]
171+
LLM_PROC -. "Redis Pub/Sub" .- REDIS
172+
UI_PROC -. "Redis Pub/Sub" .- REDIS
173+
174+
MAIN -->|"SIGINT / Ctrl+Q"| SHUTDOWN["Graceful Shutdown"]
175+
SHUTDOWN -->|"ch:system → shutdown"| REDIS
176+
177+
style REDIS fill:#dc382c,color:#fff
178+
style MAIN fill:#333,color:#fff
179+
style SHUTDOWN fill:#e67700,color:#fff
180+
```
181+
182+
---
183+
184+
## Project Structure
185+
186+
```
187+
MultiverseNoteV2/
188+
├── pyproject.toml # UV-managed dependencies
189+
├── src/
190+
│ └── multiverse_note/
191+
│ ├── conf/ # Hydra configuration (bundled in package)
192+
│ ├── main.py # Entry point: launches all nodes
193+
│ ├── models/ # Data models (dataclasses)
194+
│ │ ├── branch.py # Branch model
195+
│ │ ├── node.py # ConversationNode model
196+
│ │ └── tag.py # Tag model
197+
│ ├── store/ # Redis storage layer
198+
│ │ ├── redis_client.py # Redis connection wrapper
199+
│ │ ├── branch_store.py # Branch CRUD operations
200+
│ │ ├── node_store.py # ConversationNode CRUD
201+
│ │ └── tag_store.py # Tag CRUD operations
202+
│ ├── nodes/ # Isolated process nodes
203+
│ │ ├── base.py # Abstract BaseNode class
204+
│ │ ├── llm_node.py # LLM processing node
205+
│ │ └── context_node.py # Context & branch management node
206+
│ ├── ui/ # Terminal UI (Textual)
207+
│ │ ├── app.py # Main Textual App
208+
│ │ ├── screens/
209+
│ │ │ ├── conversation.py # Active conversation screen
210+
│ │ │ ├── branch_tree.py # Branch navigation/overview
211+
│ │ │ └── tag_select.py # Tag selection modal
212+
│ │ └── widgets/
213+
│ │ ├── message_view.py # Renders conversation messages
214+
│ │ ├── context_bar.py # Shows loaded context refs
215+
│ │ └── tag_badge.py # Colored tag display
216+
│ └── utils/
217+
│ └── logging.py # File-based logging utility
218+
├── tests/ # Test suite (51 tests)
219+
│ ├── conftest.py # fakeredis fixtures
220+
│ ├── test_models/
221+
│ ├── test_store/
222+
│ └── test_nodes/
223+
└── logs/ # Git-ignored log output
224+
```
225+
226+
---
227+
228+
## Redis Schema
229+
230+
```mermaid
231+
erDiagram
232+
BRANCH {
233+
int id PK
234+
string name
235+
string created_at
236+
int parent_branch_id FK
237+
string status
238+
}
239+
BRANCH ||--o{ NODE : "branch:id:nodes"
240+
BRANCH ||--o{ BRANCH : "branch:id:context_refs"
241+
242+
NODE {
243+
int id PK
244+
int branch_id FK
245+
string role
246+
string content
247+
string title
248+
string summary
249+
string timestamp
250+
}
251+
NODE ||--o{ TAG : "node:id:tags"
252+
253+
TAG {
254+
int id PK
255+
string name
256+
string color
257+
string created_at
258+
}
259+
```
260+
261+
### Key Patterns
262+
263+
| Key | Type | Description |
264+
|-----|------|-------------|
265+
| `counter:branch` | int | Auto-increment ID for branches |
266+
| `counter:node` | int | Auto-increment ID for nodes |
267+
| `counter:tag` | int | Auto-increment ID for tags |
268+
| `branch:{id}` | Hash | Branch metadata |
269+
| `branch:{id}:nodes` | List | Ordered node IDs in a branch |
270+
| `branch:{id}:context_refs` | Set | Referenced branch IDs as context |
271+
| `node:{id}` | Hash | Conversation node data |
272+
| `node:{id}:tags` | Set | Tag IDs assigned to a node |
273+
| `tag:{id}` | Hash | Tag metadata |
274+
| `tags:all` | Set | All tag IDs |
275+
276+
### Pub/Sub Channels
277+
278+
```mermaid
279+
flowchart TB
280+
subgraph Channels
281+
direction LR
282+
ui_in["ch:user_input"]
283+
llm_req["ch:llm_request"]
284+
llm_res["ch:llm_response"]
285+
br_ev["ch:branch_event"]
286+
tag_ev["ch:tag_event"]
287+
sys["ch:system"]
288+
end
289+
290+
UI(["Terminal UI"]) -->|user text| ui_in
291+
ui_in -->|consumed by| CTX(["ContextNode"])
292+
CTX -->|assembled context| llm_req
293+
llm_req -->|consumed by| LLM(["LLMNode"])
294+
LLM -->|response| llm_res
295+
llm_res -->|displayed by| UI
296+
297+
UI -->|create/switch| br_ev
298+
br_ev -->|handled by| CTX
299+
UI -->|create/assign| tag_ev
300+
tag_ev -->|handled by| CTX
301+
302+
MAIN(["main.py"]) -->|shutdown| sys
303+
sys -->|stops| CTX
304+
sys -->|stops| LLM
305+
sys -->|stops| UI
306+
```
307+
308+
---
309+
310+
## Testing
311+
312+
Tests use [fakeredis](https://github.com/cunla/fakeredis) to simulate Redis without a running server.
313+
314+
```bash
315+
# Run all 51 tests
316+
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run pytest tests/ -v
317+
```
318+
319+
Test coverage includes:
320+
- **Model tests** — Serialization roundtrips for Branch, ConversationNode, Tag
321+
- **Store tests** — Full CRUD operations with fakeredis
322+
- **Node tests** — BaseNode lifecycle, ContextNode branch/context/tag management, LLMNode with mocked litellm
323+
324+
---
325+
326+
## Key Libraries
327+
328+
| Purpose | Library |
329+
|---------|---------|
330+
| Terminal UI | [textual](https://textual.textualize.io/) |
331+
| Redis | [redis-py](https://github.com/redis/redis-py) with hiredis |
332+
| LLM Integration | [litellm](https://github.com/BerriAI/litellm) |
333+
| Configuration | [hydra-core](https://hydra.cc/) |
334+
| Package Management | [uv](https://github.com/astral-sh/uv) |
335+
| Testing | [pytest](https://pytest.org/) + [fakeredis](https://github.com/cunla/fakeredis) |
336+
337+
---
338+
339+
## License
340+
341+
This project is released under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.

0 commit comments

Comments
 (0)