A self-hosted, open-source chat application where every conversation is a git repo, every message is a commit, and forking a conversation creates a git branch.
Built with Next.js and powered by Claude API.
GitChat treats conversations like code — with full version control. Instead of a flat message history, each conversation is a local git repository:
- Messages are commits — every user message and AI response is stored as a git commit
- Branches are conversation paths — fork any conversation at any point to explore a different direction
- The tree is your map — an interactive sidebar visualizes all branches, letting you navigate your conversation's history
This means you can:
- Ask the same question and get different answers (regenerate)
- Branch off an AI response to explore a tangent
- Delete a dead-end and keep going from where things were good
- See every path you've explored in a visual tree
- Node.js 18+
- Git installed and available in PATH
- An Anthropic API key from console.anthropic.com
# Clone the repo
git clone https://github.com/your-username/gitchat.git
cd gitchat
# Install dependencies
npm install
# Configure your API key
cp .env.example .env.local
# Edit .env.local and add your ANTHROPIC_API_KEY
# Start the dev server
npm run devOpen http://localhost:1129 to start chatting.
| Variable | Required | Default | Description |
|---|---|---|---|
ANTHROPIC_API_KEY |
Yes | — | Your Anthropic API key (starts with sk-ant-) |
ANTHROPIC_MODEL |
No | claude-sonnet-4-6 |
Claude model to use |
CONVERSATIONS_DIR |
No | ./data/conversations |
Where conversation repos are stored |
Send messages and receive streaming AI responses in real-time. The full conversation history of the active branch is always sent as context, so Claude remembers everything from that conversation path.
Fork from any AI response to write a different follow-up question. The new branch inherits the full conversation history up to that point.
Regenerate from any user message to get a different AI answer. Click the regenerate button (or pick a character persona from the dropdown) and a new branch is created from your question with a fresh AI response streamed in real-time.
Branch names are auto-generated as memorable two-word combos (e.g. azure-dolphin, quiet-zebra) and can be renamed at any time.
The sidebar shows your entire conversation as an interactive tree graph:
- User nodes (blue) and AI nodes (purple) connected by edges
- Pan and zoom to navigate large conversation trees
- Hover any node to preview its content
- Click to jump to that message in the chat
- Search across all branches to find and highlight matching messages
- Delete a message node to remove it and everything after it (with cascade confirmation)
The tree panel is collapsible and resizable — drag the divider or toggle it with the tree button in the header.
Create custom AI personas that modify how Claude responds during regeneration:
- Default characters: Philosopher and Physicist are included out of the box
- Custom characters: Create your own with a name and description (system prompt modifier)
- AI prompt helper: Click "Help from AI" when creating a character — describe the concept in plain language and Claude generates a proper system prompt for you
- Editable: Click any character to expand and edit its description inline
- Per-conversation: Enable or disable characters for each conversation with a toggle switch — only enabled characters appear in the regenerate dropdown
- Auto-inheritance: Once you regenerate with a character, all follow-up messages on that branch automatically continue in that character's persona
- Tree tags: AI responses generated with a character show a purple name tag on their tree node, so you can see which branches are "in character"
- Quick access: The regenerate dropdown shows all enabled characters for one-click selection
Characters are stored globally in data/characters.json and managed from the character panel in the conversation sidebar.
- Create new conversations from the home page
- Rename conversations inline from the conversation list
- Delete conversations permanently (removes the entire git repo)
- Switch branches via the branch selector dropdown with rename support
Delete messages from any point in a conversation:
- A small
×button appears on user message nodes in the tree on hover - AI answer nodes can also be deleted when there are multiple answers from the same user message (from regeneration)
- Deletion is destructive (
git reset --hard) — the messages are permanently removed - Cascade delete: any branches forked from the deleted messages are also removed
- A confirmation dialog shows exactly what will be affected before proceeding
data/
├── conversations/
│ └── <uuid>/ # Each conversation is a git repo
│ ├── .git/ # Git internals
│ ├── conversation.json # Metadata (title, createdAt)
│ ├── .character-config.json # Per-conversation character settings
│ └── messages/
│ ├── 2026-03-22T10-00-00-user.md
│ ├── 2026-03-22T10-00-01-assistant.md
│ └── ...
└── characters.json # Global character definitions
- Framework: Next.js 14 (App Router)
- UI: React 18 + Tailwind CSS
- AI: Anthropic Claude API with SSE streaming
- Storage: Git (no database — git is the database)
- Markdown: react-markdown with remark-gfm
- Branch Names: unique-names-generator
- No database — every piece of data is either a git commit, a git branch, or a JSON file
- Full context — the AI always receives the complete conversation history from root to branch tip
- Streaming everywhere — both normal chat and regeneration stream tokens in real-time via Server-Sent Events
- Destructive deletes — when you delete, it's gone (
git reset --hard). The tree visualization makes it clear what you're removing
npm run dev # Start development server
npm run build # Build for production
npm run start # Start production server
npm run lint # Run ESLint
npm test # Run testsOpen source. Self-hosted. Your conversations stay on your machine.