Parlor - a private parlor for AI conversation
Project description
Parlor
A private parlor for AI conversation.
Self-hosted ChatGPT-style web UI that connects to any OpenAI-compatible API.
Install with pip. Run locally. Own your data.
Why Parlor?
Your company's AI UI is clunky. Cloud-hosted alternatives see your data. Parlor gives you a fast, private, locally-run chat interface that connects to any OpenAI-compatible endpoint --- your company's internal API, OpenAI, Azure, Ollama, LM Studio, or anything else that speaks the OpenAI protocol.
- One command install ---
pip install parlor - Zero cloud dependency --- everything runs on your machine
- Conversations persist --- SQLite database, local filesystem
- MCP tool support --- extend your AI with external tools
- Enterprise security --- CSP, CSRF protection, rate limiting, input sanitization
Quick Start
pip install parlor
Create ~/.ai-chat/config.yaml:
ai:
base_url: "https://your-ai-endpoint/v1"
api_key: "your-api-key"
model: "gpt-4"
Test your connection:
parlor --test
Launch:
parlor
Your browser opens automatically to http://127.0.0.1:8080.
Features
Conversations
- Create, rename, search, export, and delete conversations
- Full-text search across all messages and titles
- Export any conversation to Markdown
- Auto-generated titles from your first message
- Keyboard shortcuts:
Ctrl+Shift+N(new),Escape(stop generation)
Rich Rendering
- Markdown with full GFM support
- Code blocks with syntax highlighting and one-click copy
- LaTeX math rendering (inline and display)
- Tables, lists, blockquotes --- all rendered beautifully
File Attachments
- Drag-and-drop or click to attach
- Supports 30+ file types: code, documents, images, data files
- Up to 10 files per message, 10 MB each
- Image previews inline
MCP Tool Integration
- Connect stdio or SSE-based MCP servers
- AI can call tools during conversation
- Tool calls displayed with expandable input/output
- Configure multiple servers in
config.yaml
Streaming
- Real-time token-by-token streaming via SSE
- Stop generation mid-response with Escape or the stop button
- Thinking indicator while the AI processes
Configuration
Config File
~/.ai-chat/config.yaml
ai:
base_url: "https://your-ai-endpoint/v1"
api_key: "your-api-key"
model: "gpt-4"
system_prompt: "You are a helpful assistant."
verify_ssl: true # set false for self-signed certs
app:
host: "127.0.0.1"
port: 8080
data_dir: "~/.ai-chat"
# Optional: MCP tool servers
mcp_servers:
- name: "my-tools"
transport: "stdio"
command: "npx"
args: ["-y", "@my-org/mcp-tools"]
- name: "remote-tools"
transport: "sse"
url: "https://mcp-server.example.com/sse"
Environment Variables
Every config option has an env var override:
| Variable | Default | Description |
|---|---|---|
AI_CHAT_BASE_URL |
--- | AI API endpoint (required) |
AI_CHAT_API_KEY |
--- | API authentication key (required) |
AI_CHAT_MODEL |
gpt-4 |
Model name |
AI_CHAT_SYSTEM_PROMPT |
You are a helpful assistant. |
System prompt |
AI_CHAT_VERIFY_SSL |
true |
SSL certificate verification |
Settings UI
Click the gear icon in the sidebar to change model and system prompt at runtime. Available models are fetched live from your API.
CLI
parlor # Start the server and open browser
parlor --test # Test connection: list models, send a test prompt, exit
parlor --help # Show help
--test Output
Config:
Endpoint: https://your-ai-endpoint/v1
Model: gpt-4
SSL: enabled
1. Listing models...
OK - 12 model(s) available
- gpt-4
- gpt-4-turbo
- gpt-3.5-turbo
...
2. Sending test prompt to gpt-4...
OK - Response: Hello! How can I help you today?
All checks passed.
Security
Parlor is hardened for use on corporate networks and shared machines.
| Layer | Protection |
|---|---|
| Authentication | Random session token with HttpOnly cookies, HMAC-SHA256 timing-safe comparison |
| Content Security Policy | script-src 'self', frame-ancestors 'none', no inline scripts |
| Headers | X-Frame-Options DENY, X-Content-Type-Options nosniff, strict Referrer-Policy, Permissions-Policy |
| Input Sanitization | DOMPurify on all rendered HTML, parameterized SQL, UUID validation |
| Rate Limiting | 120 req/min per IP with LRU eviction |
| Body Size Limit | 15 MB max request size |
| CORS | Locked to configured origin, explicit method/header allowlist |
| File Safety | MIME type allowlist, path traversal prevention, forced download for non-image types |
| MCP Safety | SSRF protection with DNS resolution, shell metacharacter rejection in tool args |
| Subresource Integrity | SHA-384 hashes on all vendor scripts |
| API Surface | OpenAPI/Swagger docs disabled in production |
Data Storage
All data stays on your machine:
~/.ai-chat/
config.yaml # Your configuration (permissions: 0600)
chat.db # SQLite database with WAL journaling
attachments/ # Uploaded files organized by conversation
The data directory is created with 0700 permissions (owner-only access).
Supported File Types
Code: .py .js .ts .java .c .cpp .h .hpp .rs .go .rb .php .sh .bat .ps1 .sql .css
Data: .json .yaml .yml .csv .xml .toml .ini .cfg .log
Documents: .txt .md .pdf
Images: .png .jpg .jpeg .gif .webp
API
Parlor exposes a REST API on the same port. All endpoints require authentication.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/conversations |
List conversations (with optional ?search=) |
POST |
/api/conversations |
Create new conversation |
GET |
/api/conversations/:id |
Get conversation with messages |
PATCH |
/api/conversations/:id |
Rename conversation |
DELETE |
/api/conversations/:id |
Delete conversation and attachments |
GET |
/api/conversations/:id/export |
Download as Markdown |
POST |
/api/conversations/:id/chat |
Stream chat (SSE) |
POST |
/api/conversations/:id/stop |
Cancel active generation |
GET |
/api/attachments/:id |
Download attachment |
GET |
/api/config |
Get current config |
PATCH |
/api/config |
Update model/system prompt |
POST |
/api/config/validate |
Test connection and list models |
GET |
/api/mcp/tools |
List available MCP tools |
Development
git clone https://github.com/troylar/parlor.git
cd parlor
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Lint & format
ruff check src/ tests/
ruff format src/ tests/
Tech Stack
| Component | Technology |
|---|---|
| Backend | Python 3.10+, FastAPI, Uvicorn |
| Frontend | Vanilla JS, marked.js, highlight.js, KaTeX, DOMPurify |
| Database | SQLite with FTS5 full-text search |
| AI SDK | OpenAI Python SDK (async) |
| MCP | Model Context Protocol SDK |
| Streaming | Server-Sent Events (SSE) |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file parlor-0.3.0.tar.gz.
File metadata
- Download URL: parlor-0.3.0.tar.gz
- Upload date:
- Size: 445.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4979f5f0c1e92a61c3e04bab303ed5c3212fccb999a3d08f67ef215804fa56ff
|
|
| MD5 |
44e63c5ef9d4b67ecfd15a255f621037
|
|
| BLAKE2b-256 |
594612bbac2de0212717ae03d7b25e17188a4078f97fa3916e7e51eefffb93ac
|
File details
Details for the file parlor-0.3.0-py3-none-any.whl.
File metadata
- Download URL: parlor-0.3.0-py3-none-any.whl
- Upload date:
- Size: 452.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b19e3e5aff7013853b724ac5f09e65f01e074753f91b06cc40d5cd9741d521dd
|
|
| MD5 |
2a77ed61183e82f19c372f421e767714
|
|
| BLAKE2b-256 |
992168bd80d863add82d75ebbe4784c7c7ce6a26c8236920e581967f564cfffb
|