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.
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.
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.
flowchart LR
UI["Terminal UI\n(Textual)"]
CTX["ContextNode\n(Branch & Context)"]
LLM["LLMNode\n(litellm)"]
R[(Redis)]
UI -- "ch:user_input" --> R
R -- "ch:user_input" --> CTX
CTX -- "store user node\n+ assemble context" --> R
CTX -- "ch:llm_request" --> R
R -- "ch:llm_request" --> LLM
LLM -- "ch:llm_response" --> R
R -- "ch:llm_response" --> UI
style R fill:#dc382c,color:#fff
style UI fill:#1a8cff,color:#fff
style CTX fill:#2b8a3e,color:#fff
style LLM fill:#7c3aed,color:#fff
gitGraph
commit id: "user: What is Rust?"
commit id: "assistant: Rust is a..."
branch deep-dive
commit id: "user: Explain ownership"
commit id: "assistant: Ownership in Rust..."
branch ownership-examples
commit id: "user: Show me borrowing"
commit id: "assistant: Here is an example..."
checkout deep-dive
commit id: "user: What about lifetimes?"
commit id: "assistant: Lifetimes ensure..."
checkout main
commit id: "user: Compare Rust vs Go"
commit id: "assistant: Both are systems..."
- Branch Management — Create, switch, and navigate conversation branches with parent-child relationships
- Context References — New branches can reference existing branches, loading their conversation history as context for the LLM
- Tag System — Tag conversation pairs with colored labels for organization and retrieval
- Multi-Provider LLM — Supports OpenAI, Anthropic, and local models via litellm
- Terminal UI — Full keyboard-navigable TUI built with Textual
- Isolated Nodes — Each component runs as a separate process communicating via Redis
- File-based Logging — All logs written to rotating files, no terminal output clutter
- Python >= 3.11
- Redis server running locally (default:
localhost:6379) - uv package manager
- An LLM API key (e.g.
OPENAI_API_KEYfor the default OpenAI provider)
# Clone the repository
git clone https://github.com/AhmadCodes/MultiverseNoteV2.git
cd MultiverseNoteV2
# Install dependencies
uv syncredis-serverexport OPENAI_API_KEY="sk-..."uv run multiverse| Key | Action |
|---|---|
Enter |
Send message |
Ctrl+B |
Open branch tree |
Ctrl+Q |
Quit |
Escape |
Close modal / Go back |
N |
New branch (in branch tree) |
Configuration is managed via Hydra with composable YAML files in src/multiverse_note/conf/.
Default is OpenAI. To use Anthropic:
uv run multiverse llm=anthropicOr override individual settings:
uv run multiverse llm.model=openai/gpt-4o-mini llm.temperature=0.5uv run multiverse redis.host=myhost redis.port=6380 redis.db=1src/multiverse_note/conf/
├── config.yaml # Main config (composes all groups)
├── redis/default.yaml # host, port, db, password
├── llm/
│ ├── default.yaml # Default provider (OpenAI)
│ ├── openai.yaml
│ └── anthropic.yaml
├── ui/default.yaml # Theme, layout preferences
└── logging/default.yaml # Log level, file path, rotation
flowchart TB
MAIN["main.py\n@hydra.main"]
MAIN -->|"multiprocessing.Process\n(daemon)"| CTX_PROC["ContextNode Process"]
MAIN -->|"multiprocessing.Process\n(daemon)"| LLM_PROC["LLMNode Process"]
MAIN -->|"runs in main process\n(needs terminal)"| UI_PROC["MultiverseApp (Textual)"]
CTX_PROC -. "Redis Pub/Sub" .- REDIS[(Redis)]
LLM_PROC -. "Redis Pub/Sub" .- REDIS
UI_PROC -. "Redis Pub/Sub" .- REDIS
MAIN -->|"SIGINT / Ctrl+Q"| SHUTDOWN["Graceful Shutdown"]
SHUTDOWN -->|"ch:system → shutdown"| REDIS
style REDIS fill:#dc382c,color:#fff
style MAIN fill:#333,color:#fff
style SHUTDOWN fill:#e67700,color:#fff
MultiverseNoteV2/
├── pyproject.toml # UV-managed dependencies
├── src/
│ └── multiverse_note/
│ ├── conf/ # Hydra configuration (bundled in package)
│ ├── main.py # Entry point: launches all nodes
│ ├── models/ # Data models (dataclasses)
│ │ ├── branch.py # Branch model
│ │ ├── node.py # ConversationNode model
│ │ └── tag.py # Tag model
│ ├── store/ # Redis storage layer
│ │ ├── redis_client.py # Redis connection wrapper
│ │ ├── branch_store.py # Branch CRUD operations
│ │ ├── node_store.py # ConversationNode CRUD
│ │ └── tag_store.py # Tag CRUD operations
│ ├── nodes/ # Isolated process nodes
│ │ ├── base.py # Abstract BaseNode class
│ │ ├── llm_node.py # LLM processing node
│ │ └── context_node.py # Context & branch management node
│ ├── ui/ # Terminal UI (Textual)
│ │ ├── app.py # Main Textual App
│ │ ├── screens/
│ │ │ ├── conversation.py # Active conversation screen
│ │ │ ├── branch_tree.py # Branch navigation/overview
│ │ │ └── tag_select.py # Tag selection modal
│ │ └── widgets/
│ │ ├── message_view.py # Renders conversation messages
│ │ ├── context_bar.py # Shows loaded context refs
│ │ └── tag_badge.py # Colored tag display
│ └── utils/
│ └── logging.py # File-based logging utility
├── tests/ # Test suite (51 tests)
│ ├── conftest.py # fakeredis fixtures
│ ├── test_models/
│ ├── test_store/
│ └── test_nodes/
└── logs/ # Git-ignored log output
erDiagram
BRANCH {
int id PK
string name
string created_at
int parent_branch_id FK
string status
}
BRANCH ||--o{ NODE : "branch:id:nodes"
BRANCH ||--o{ BRANCH : "branch:id:context_refs"
NODE {
int id PK
int branch_id FK
string role
string content
string title
string summary
string timestamp
}
NODE ||--o{ TAG : "node:id:tags"
TAG {
int id PK
string name
string color
string created_at
}
| Key | Type | Description |
|---|---|---|
counter:branch |
int | Auto-increment ID for branches |
counter:node |
int | Auto-increment ID for nodes |
counter:tag |
int | Auto-increment ID for tags |
branch:{id} |
Hash | Branch metadata |
branch:{id}:nodes |
List | Ordered node IDs in a branch |
branch:{id}:context_refs |
Set | Referenced branch IDs as context |
node:{id} |
Hash | Conversation node data |
node:{id}:tags |
Set | Tag IDs assigned to a node |
tag:{id} |
Hash | Tag metadata |
tags:all |
Set | All tag IDs |
flowchart TB
subgraph Channels
direction LR
ui_in["ch:user_input"]
llm_req["ch:llm_request"]
llm_res["ch:llm_response"]
br_ev["ch:branch_event"]
tag_ev["ch:tag_event"]
sys["ch:system"]
end
UI(["Terminal UI"]) -->|user text| ui_in
ui_in -->|consumed by| CTX(["ContextNode"])
CTX -->|assembled context| llm_req
llm_req -->|consumed by| LLM(["LLMNode"])
LLM -->|response| llm_res
llm_res -->|displayed by| UI
UI -->|create/switch| br_ev
br_ev -->|handled by| CTX
UI -->|create/assign| tag_ev
tag_ev -->|handled by| CTX
MAIN(["main.py"]) -->|shutdown| sys
sys -->|stops| CTX
sys -->|stops| LLM
sys -->|stops| UI
Tests use fakeredis to simulate Redis without a running server.
# Run all 51 tests
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run pytest tests/ -vTest coverage includes:
- Model tests — Serialization roundtrips for Branch, ConversationNode, Tag
- Store tests — Full CRUD operations with fakeredis
- Node tests — BaseNode lifecycle, ContextNode branch/context/tag management, LLMNode with mocked litellm
| Purpose | Library |
|---|---|
| Terminal UI | textual |
| Redis | redis-py with hiredis |
| LLM Integration | litellm |
| Configuration | hydra-core |
| Package Management | uv |
| Testing | pytest + fakeredis |
This project is released under the Apache License 2.0. See the LICENSE file for details.