Multi-Character Conversation System with Claude Code
A TRPG-style game master system that orchestrates multi-character conversations with AI providers (Claude, Gemini, Droid), maintaining narrative history and workspace context.
What This Skill Does
This skill implements a persona chatbot system where:
AI acts as a Game Master coordinating multiple character personasConversations are recorded as narrative markdown storiesFull workspace context and conversation history are maintainedWebSocket-based real-time communication between Python backend and web frontendJWT authentication with admin account managementMultiple AI provider support (Claude CLI, Gemini API, Droid)Architecture Overview
**Backend (Python):**
`server/websocket_server.py` - WebSocket + HTTP server entry point`server/core/` - Session management, auth, app context`server/handlers/` - Business logic (Claude/Gemini/Droid, history, workspace, database)`server/ws/` - WebSocket routing and action handlers**Frontend (Static):**
`web/` - HTML/JS/CSS served by Python HTTP helperReal-time updates via WebSocket at ws://127.0.0.1:8765**Storage:**
`persona_data/stories/` - Saved narrative markdown files`chatbot_workspace/` - Workspace with CLAUDE.md contextSQLite database for authentication and historySetup Instructions
1. Environment Setup
```bash
Create virtual environment
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Install dependencies
pip install -r requirements.txt
Claude CLI authentication (first time only)
claude auth login
```
2. Configuration
```bash
Copy environment template
cp .env.example .env
Edit .env with required values:
- APP_JWT_SECRET (required if using APP_LOGIN_PASSWORD)
- APP_LOGIN_PASSWORD (optional, for simple auth)
- FACTORY_AUTH_DIR, CLAUDE_AUTH_DIR, GEMINI_AUTH_DIR (for Docker)
```
3. Create Admin Account
**For local development:**
```python
python3 -c "
from server.handlers.db_handler import DBHandler
import asyncio
async def create_admin():
db = DBHandler('./data')
await db.initialize()
success = await db.create_admin_user('admin', 'your_password')
print('Admin created' if success else 'Already exists')
asyncio.run(create_admin())
"
```
**For Docker (must be run inside container):**
```bash
docker compose exec persona-chatbot python3 -c "
from server.handlers.db_handler import DBHandler
import asyncio
async def create_admin():
db = DBHandler('./data')
await db.initialize()
success = await db.create_admin_user('admin', 'password')
print('Admin created' if success else 'Already exists')
asyncio.run(create_admin())
"
```
4. Run the Application
**Local development:**
```bash
python3 -m server.websocket_server
Access at:
- HTTP UI: http://127.0.0.1:9000
- WebSocket: ws://127.0.0.1:8765
```
**Docker:**
```bash
Copy and configure docker-compose
cp docker-compose.yml.example docker-compose.yml
Start containers
docker compose up --build
Ports follow .env settings (HTTP_PORT, WS_PORT)
```
Key Features
AI Provider Integration
The system supports three AI providers:
1. **Claude (via Claude CLI)** - Primary provider using local Claude CLI
2. **Droid** - Alternative Claude-based provider
3. **Gemini** - Google's Gemini API integration
Switch providers via WebSocket actions or workspace configuration.
Conversation History Management
Automatic conversation recording to markdown filesHistory retrieval and context injectionFile-based narrative storage in `persona_data/stories/`Timestamp-based organizationWorkspace Context
Reads `chatbot_workspace/CLAUDE.md` for contextMaintains conversation state across sessionsSupports mode switching (narrative/coding)Authentication
JWT-based authentication with:
Access tokens (short-lived)Refresh tokens (long-lived)Admin account managementOptional password protectionTesting
Manual Smoke Tests
```bash
Test all providers end-to-end
python scripts/ws_chat_test.py --provider claude --prompt "Test Claude"
python scripts/ws_chat_test.py --provider droid --prompt "Test Droid"
python scripts/ws_chat_test.py --provider gemini --prompt "Test Gemini"
```
Unit Tests
```bash
Install pytest
pip install pytest
Run tests
pytest -q
Tests should be in tests/ mirroring source structure
Example: tests/handlers/test_history_handler.py
```
Development Guidelines
Code Style
**Python:**
Follow PEP 8 with 4-space indentationUse type hints where practical`snake_case` for modules/functions`PascalCase` for classes`UPPER_SNAKE_CASE` for constantsUse `logging` instead of `print`Include docstrings for public functions**JavaScript:**
ES6+ syntax (`const`/`let`)Small, pure functionsSeparate DOM selectors from rendering logicCommit Conventions
Use imperative mood with scope prefix: `fix(server): description`Write commit messages in KoreanExample: `fix(server): websockets v13 연결 종료 처리`Pull Request Guidelines
Include problem/solution summary (in Korean)Provide local run stepsAdd screenshots for UI changesLink related issuesKeep PRs focused (avoid unrelated refactors)Verify app runs before requesting reviewMCP Tools Integration
Serena MCP (Code Navigation)
```bash
Install once per machine
uvx --from git+https://github.com/oraios/serena serena --help
Create project (local only, don't commit .serena/)
serena project create --name persona-chatbot --language python --index .
Start MCP server
serena start-mcp-server --transport stdio
Call activate_project at session start
```
Use Serena for:
Code analysis and refactoringReference tracingSymbol/call-graph workCross-file code navigationContext7 MCP (Official Docs)
Use Context7 for:
External framework documentation (FastAPI, websockets, SQLAlchemy)Latest patterns and best practices"How to use X" questionsVerifying library usage instead of relying on memorySecurity Notes
Never commit secrets or `.env` filesUse `APP_JWT_SECRET` when enabling `APP_LOGIN_PASSWORD`Default bind host is `127.0.0.1` (localhost only)Admin accounts must be created inside Docker containers to avoid SQLite locksFor Docker, use host-absolute auth directories in `.env`Document Synchronization
This repository uses a base document system:
SSOT: `docs/agents_base_en.md`Run `bash scripts/sync_agents_from_base.sh` to sync agent-specific replicasNever edit replicas directly (AGENTS.md, CLAUDE.md, GEMINI.md, .github/copilot-instructions.md)Project Structure
```
├── server/ # Python backend
│ ├── websocket_server.py # Entry point
│ ├── core/ # Core utilities
│ ├── handlers/ # Business logic
│ ├── http/ # HTTP server
│ └── ws/ # WebSocket routing
├── web/ # Static frontend
│ ├── index.html
│ ├── app.js
│ └── style.css
├── persona_data/
│ └── stories/ # Saved narratives
├── chatbot_workspace/ # Workspace context
├── scripts/ # Utility scripts
├── tests/ # Test suite
└── docs/ # Documentation
```
Troubleshooting
**WebSocket connection fails:**
Verify server is running on 127.0.0.1:8765Check firewall settingsEnsure ports are not in use**Authentication errors:**
Verify `APP_JWT_SECRET` is set when using password protectionCheck admin account was created successfullyVerify token expiration settings**AI provider errors:**
Claude: Run `claude auth login` if authentication failsGemini: Verify API key is set correctlyCheck provider-specific auth directories in `.env`**SQLite lock errors:**
For Docker, always create admin accounts inside containerCheck database file permissions in `./data` directoryLanguage Guidelines
**Code/Comments/Commits**: Korean (한국어)**Identifiers**: English for interoperability**Documentation**: Korean for user-facing, English for base docs**Team communication**: Korean by defaultVersion Information
Python: 3.8+WebSocket: websockets v13+Frontend: Vanilla JS (ES6+)Database: SQLiteAuthentication: JWTAI Providers: Claude CLI, Gemini API, Droid