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.
Quick Start • Features • Themes • Security • API
Why Parlor?
Your company's AI chat UI sucks. You know it. We know it. Parlor replaces it with something you'll actually want to use.
It connects to any OpenAI-compatible endpoint --- your company's internal API, OpenAI, Azure, Ollama, LM Studio, or anything else that speaks the OpenAI protocol. Built to OWASP ASVS L1 standards because your conversations deserve real security, not security theater.
One command. No cloud. No telemetry. No compromise.
pip install parlor
Quick Start
1. Install
pip install parlor
2. Configure --- create ~/.ai-chat/config.yaml:
ai:
base_url: "https://your-ai-endpoint/v1"
api_key: "your-api-key"
model: "gpt-4"
3. Verify your connection:
parlor --test
4. Launch:
parlor
Your browser opens to http://127.0.0.1:8080. That's it. You're done.
Features
Conversations
| Create, rename, search, delete | Full conversation lifecycle |
| Full-text search | FTS5-powered search across all messages and titles |
| Fork at any message | Explore different directions from any point |
| Edit & regenerate | Fix a message and re-run from there |
| Export to Markdown | One-click download of any conversation |
| Auto-titles | AI generates a title from your first message |
| Keyboard-first | Ctrl+Shift+N new chat, Escape stop generation |
Projects
Group conversations under projects with custom system prompts and per-project model selection. Your coding project uses Claude with a developer prompt. Your writing project uses GPT-4 with an editorial voice. Each project is its own world.
Organization
|
Folders
|
Tags
|
Shared Databases
Connect multiple SQLite databases for team or topic-based separation. Each database is fully independent --- its own conversations, attachments, and history.
- Visual file browser for selecting database paths
- Copy conversations between databases
- Switch databases from the sidebar
Rich Rendering
Markdown -> Full GFM with tables, lists, blockquotes
Code blocks -> Syntax highlighting + one-click copy
LaTeX math -> Inline ($x^2$) and display ($$\int$$)
Images -> Inline previews for attached images
File Attachments
Drag-and-drop or click to attach. 30+ file types supported --- code, documents, images, data files. Up to 10 files per message, 10 MB each. Magic-byte verification ensures files are what they claim to be.
MCP Tool Integration
Connect stdio or SSE-based MCP servers. Your AI gains access to external tools --- databases, APIs, file systems, anything with an MCP adapter. Tool calls render with expandable input/output so you see exactly what happened.
mcp_servers:
- name: "my-tools"
transport: "stdio"
command: "npx"
args: ["-y", "@my-org/mcp-tools"]
Streaming
Real-time token-by-token streaming via Server-Sent Events. Stop generation mid-response with Escape or the stop button. A thinking indicator keeps you informed while the AI processes.
Command Palette
Cmd+K / Ctrl+K opens a Raycast-style command palette. Search conversations, switch themes, create projects, jump to settings --- all without touching the mouse. Fuzzy matching makes it fast.
Themes
Four built-in themes, each with a distinct visual identity. Switch instantly via settings or command palette.
| Theme | Vibe | |
|---|---|---|
| Midnight | Premium tech dark --- think Linear, Raycast | Default |
| Dawn | Warm editorial light --- think Notion in sunlight | Light |
| Aurora | Living gradient dark with animated accents | Showstopper |
| Ember | Warm luxury dark --- amber by firelight | Cozy |
Themes persist across sessions. Glassmorphism, multi-layered shadows, micro-animations on hover/focus, gradient text effects, and smooth 0.5s cross-fade transitions between themes.
Responsive Design
| Breakpoint | Target | Behavior |
|---|---|---|
| 1400px+ | Large desktop | Wider messages, expanded sidebar |
| 769-1399px | Desktop | Default layout |
| 768-1024px | Tablet | Compact sidebar, full-width messages |
| 0-767px | Mobile | Slide-over sidebar with hamburger menu |
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: shared databases
shared_databases:
- name: "team-shared"
path: "~/shared/team.db"
# 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 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 to change model and system prompt at runtime. Available models are fetched live from your API.
CLI
parlor Launch server and open browser
parlor --test Test connection, list models, send test prompt, exit
parlor --help Show help
Example --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. Not a checkbox exercise --- real, layered defense.
| Layer | What it does |
|---|---|
| Authentication | Random session token, HttpOnly cookies, HMAC-SHA256 timing-safe comparison |
| CSRF | Per-session tokens validated on all state-changing requests |
| CSP | script-src 'self', frame-ancestors 'none', no inline scripts |
| Security Headers | X-Frame-Options DENY, X-Content-Type-Options nosniff, strict Referrer-Policy, Permissions-Policy |
| Database | Column-allowlisted SQL builder, parameterized queries, 0600 file permissions, path validation |
| Input Sanitization | DOMPurify on all rendered HTML, UUID validation on all IDs |
| Rate Limiting | 120 req/min per IP with LRU eviction |
| Body Size | 15 MB max request |
| CORS | Locked to configured origin |
| File Safety | MIME allowlist + magic-byte verification, path traversal prevention |
| MCP Safety | SSRF protection with DNS resolution, shell metacharacter rejection |
| SRI | SHA-384 hashes on all vendor scripts |
| API Surface | OpenAPI/Swagger docs disabled |
Full details in SECURITY.md.
Data Storage
Everything stays on your machine. Nothing phones home.
~/.ai-chat/
config.yaml # Configuration (permissions: 0600)
chat.db # SQLite + WAL journal (permissions: 0600)
attachments/ # Files by conversation (permissions: 0700)
The data directory is created with 0700 permissions (owner-only access). Database files are created with 0600 permissions. WAL and SHM sidecar files are locked down too.
Supported File Types
| Category | Extensions |
|---|---|
| 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 full REST API. All endpoints require authentication.
Conversations
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/conversations |
List (with ?search=, ?project_id=, ?db=) |
POST |
/api/conversations |
Create |
GET |
/api/conversations/:id |
Get with messages |
PATCH |
/api/conversations/:id |
Rename, move to folder, change model |
DELETE |
/api/conversations/:id |
Delete with attachments |
GET |
/api/conversations/:id/export |
Export as Markdown |
POST |
/api/conversations/:id/chat |
Stream chat (SSE) |
POST |
/api/conversations/:id/stop |
Cancel generation |
POST |
/api/conversations/:id/fork |
Fork at a message |
POST |
/api/conversations/:id/copy |
Copy to another database |
Messages & Attachments
| Method | Endpoint | Description |
|---|---|---|
PUT |
/api/messages/:id |
Edit a message |
DELETE |
/api/messages/:id |
Delete after position |
GET |
/api/attachments/:id |
Download attachment |
Projects, Folders, Tags
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/projects |
List projects |
POST |
/api/projects |
Create project |
PATCH |
/api/projects/:id |
Update project |
DELETE |
/api/projects/:id |
Delete project |
GET |
/api/folders |
List folders |
POST |
/api/folders |
Create folder |
PATCH |
/api/folders/:id |
Update folder |
DELETE |
/api/folders/:id |
Delete folder |
GET |
/api/tags |
List tags |
POST |
/api/tags |
Create tag |
PATCH |
/api/tags/:id |
Update tag |
DELETE |
/api/tags/:id |
Delete tag |
Config & Infrastructure
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/config |
Get current config |
PATCH |
/api/config |
Update model/system prompt |
POST |
/api/config/validate |
Test connection |
GET |
/api/models |
List available models |
GET |
/api/mcp/tools |
List MCP tools |
GET |
/api/databases |
List shared databases |
POST |
/api/databases |
Add shared database |
DELETE |
/api/databases/:name |
Remove shared database |
GET |
/api/browse |
Browse filesystem |
Development
git clone https://github.com/troylar/parlor.git
cd parlor
pip install -e ".[dev]"
pytest tests/ -v # Run tests
ruff check src/ tests/ # Lint
ruff format src/ tests/ # Format
Tech Stack
| Backend | Python 3.10+, FastAPI, Uvicorn |
| Frontend | Vanilla JS, marked.js, highlight.js, KaTeX, DOMPurify |
| Database | SQLite with FTS5 full-text search, WAL journaling |
| AI | OpenAI Python SDK (async streaming) |
| MCP | Model Context Protocol SDK (stdio + SSE) |
| Streaming | Server-Sent Events |
| Typography | Inter + JetBrains Mono (self-hosted, no external requests) |
MIT License
Built for people who care about their conversations.
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.5.0.tar.gz.
File metadata
- Download URL: parlor-0.5.0.tar.gz
- Upload date:
- Size: 634.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8b1194c26b11cb26db893e5a27e77d0127a315c2088de54d80b974aea317890
|
|
| MD5 |
9620319eee34c1a0e38647cde2f3e568
|
|
| BLAKE2b-256 |
ba649521ed571544f3ea756bda76332098193d8e9125b32038f7f040acf0fde2
|
File details
Details for the file parlor-0.5.0-py3-none-any.whl.
File metadata
- Download URL: parlor-0.5.0-py3-none-any.whl
- Upload date:
- Size: 641.0 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 |
6cd88e751168913610ea60d78e08611899d0d9d356cdc37da9ffdbe224d8fae6
|
|
| MD5 |
8c337250073a241a63f95f45ce02d2bf
|
|
| BLAKE2b-256 |
8ccaba85c0fbd4aae8b49d3dabfed19c437b1a7322db3304745fa87698b9a924
|