Skip to main content

Parlor - a private parlor for AI conversation

Project description

PyPI Version Python 3.10+ Coverage License


Parlor

A private parlor for AI conversation.

Self-hosted ChatGPT-style web UI and agentic CLI that connects to any OpenAI-compatible API.
Install with pip. Run locally. Own your data.

Quick StartWeb UICLI ChatThemesConfigSecurityAPI

Parlor - Midnight Theme


Why Parlor?

Parlor 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 ~/.parlor/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          # Web UI
parlor chat     # Terminal CLI

Your browser opens to http://127.0.0.1:8080. That's it.


Web UI

Parlor - Midnight Theme

Conversations

Create, rename, search, delete Full conversation lifecycle with double-click rename
Full-text search FTS5-powered instant search across all messages and titles
Fork at any message Branch a conversation into a new thread from any point
Rewind conversation Roll back to any message --- optionally revert file changes made by AI tools via git checkout
Edit & regenerate Edit any user message, all subsequent messages are deleted, AI regenerates from there
Export to Markdown One-click download of any conversation as .md
Auto-titles AI generates a title from your first message
Per-conversation model Switch models mid-conversation from the top bar dropdown
Copy between databases Duplicate an entire conversation (with messages + tool calls) to another database

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.

  • Project-scoped system prompt overrides the global default
  • Per-project model override (or "use global default")
  • Project-scoped folders --- each project gets its own folder hierarchy
  • Deleting a project preserves its conversations (they become unlinked, not deleted)
  • "All Conversations" view to see everything across projects

Organization

Folders

  • Nested folder hierarchy with unlimited depth
  • Add subfolders from the folder context menu
  • Collapse/expand state persists to the database
  • Depth-based indentation in the sidebar
  • Rename and delete (conversations are preserved, not deleted)
  • Project-scoped: each project gets its own folder tree

Tags

  • Color-coded labels on conversations (hex color picker)
  • Create tags inline from any conversation's tag dropdown
  • Filter the sidebar by tag
  • Visual badges with color indicators
  • Delete a tag and it's cleanly removed from all conversations

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 with directory navigation for selecting .db/.sqlite/.sqlite3 files
  • Copy conversations between databases (full message + tool call history)
  • Switch databases from the sidebar --- active database is visually indicated
  • Database names: letters, numbers, hyphens, underscores only
  • "personal" database always exists and can't be removed
  • Paths restricted to your home directory for security

Rich Rendering

Format Support
Markdown Full GFM --- tables, lists, blockquotes, strikethrough, task lists
Code blocks Syntax highlighting via highlight.js with language label + one-click copy button
LaTeX math Inline $x^2$ / \(x^2\) and display $$\int$$ / \[\int\] via KaTeX
Images Inline previews for attached images
HTML subset <kbd>, <sup>, <sub>, <dl>/<dt>/<dd> via DOMPurify allowlist

File Attachments

Drag-and-drop or click to attach. 35+ file types supported. Up to 10 files per message, 10 MB each. Every file is verified with magic-byte detection --- a renamed .exe won't sneak through as a .png.

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
  • Image attachments show inline thumbnails with file size
  • Non-image files force-download (never rendered in-browser)
  • Filenames are sanitized: path components stripped, special characters replaced

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 as expandable detail panels --- see input during execution, output + status when complete
  • Spinner animation while tools execute
  • Connected server count and total tool count shown in sidebar footer
  • SSRF protection with DNS resolution and shell metacharacter rejection on tool args
mcp_servers:
  - name: "my-tools"
    transport: "stdio"
    command: "npx"
    args: ["-y", "@my-org/mcp-tools"]
    env:
      API_KEY: "${MY_API_KEY}"
      DEBUG: "true"

  - name: "remote-tools"
    transport: "sse"
    url: "https://mcp-server.example.com/sse"

Environment variables in env values support ${VAR} expansion --- so you can reference secrets from your shell environment without hardcoding them in the config file.

Streaming & Prompt Queue

Real-time token-by-token streaming via Server-Sent Events, with prompt queuing so you never have to wait.

  • Type while streaming --- submit new messages while the AI is responding. They queue (up to 10) and process in FIFO order when the current response finishes
  • Markdown and math render live as tokens arrive
  • Raw mode toggle (eye icon in top bar) --- view unprocessed text during streaming, persists across sessions
  • Stop generation mid-response with Escape or the stop button
  • Animated thinking indicator with pulsing dots while AI processes
  • Error messages show inline with a Retry button
  • Parallel tool execution --- when the AI calls multiple tools in one response, they run concurrently via asyncio.as_completed instead of sequentially

Command Palette

Cmd+K / Ctrl+K opens a Raycast-style command palette with fuzzy matching.

Command type What it does
New Chat Create a fresh conversation
Theme: Midnight / Dawn / Aurora / Ember Switch themes instantly
Model names Switch the current model (all available models listed)
Project names Jump to a project
Recent conversations Quick-jump to your 10 most recent chats

Arrow keys to navigate, Enter to select, Escape to dismiss.

Web UI Keyboard Shortcuts

Shortcut Action
Cmd/Ctrl + K Open command palette
Ctrl + Shift + N New conversation
Escape Stop generation / close palette / close modal
Enter Send message
Shift + Enter Newline in message input

Settings UI

Click the gear icon in the sidebar to open the settings modal:

  • Model selector --- dropdown populated live from your API
  • System prompt editor --- change at runtime, persists to config.yaml
  • Theme picker --- visual cards showing each theme's color palette
  • Changes take effect immediately, no restart needed

Themes

Four built-in themes, each with a distinct visual identity. Switch instantly via settings or command palette (Cmd+K).

Midnight Default --- Premium tech dark. Deep navy-charcoal with electric blue accents. Glassmorphic sidebar.

Midnight Theme

Dawn Light --- Warm editorial light. Cream backgrounds, soft indigo-violet accents, subtle paper texture.

Dawn Theme

Aurora Showstopper --- Living gradient dark with animated CSS aurora (purple/teal/emerald). Gradient borders, animated input focus rings.

Aurora Theme

Ember Cozy --- Warm luxury dark. Amber by firelight. Brown-charcoal backgrounds, rich amber glow on focus states.

Ember Theme

Visual details:

  • Glassmorphism with backdrop-filter: blur(20px) on sidebar
  • Multi-layered shadows for depth: 0 1px 2px + 0 4px 12px
  • Micro-animations: sidebar items shift on hover, buttons glow, modals spring in
  • Gradient text effect on welcome heading
  • Smooth 0.5s cross-fade transition between themes
  • Code block copy button fades in on hover
  • Theme persists in localStorage across sessions --- no flash on reload

Responsive Design

Breakpoint Target Behavior
1400px+ Large desktop Wider messages (900px), expanded sidebar (300px)
769-1399px Desktop Default layout
768-1024px Tablet Compact sidebar (240px), full-width messages
0-767px Mobile Slide-over sidebar with hamburger menu + dark overlay

Mobile sidebar slides in with transform animation. Tap the overlay or hamburger to dismiss.


CLI Chat Mode

An agentic terminal REPL --- like Claude Code, but connected to your own API. Read files, write code, run commands, search your codebase, all from the terminal. Type while the AI is working --- messages queue and process in order. Works on macOS, Linux, and Windows.

parlor chat                     # Interactive REPL
parlor chat "explain main.py"   # One-shot mode
parlor chat -c                  # Continue last conversation
parlor chat -r <id>             # Resume a specific conversation
parlor chat -p /path/to/project # Set project root
parlor chat --no-tools          # Disable built-in tools

How It Works

  1. You type a prompt at the you> prompt (or pass one as a CLI argument for one-shot mode)
  2. A thinking spinner with elapsed timer appears while the AI generates a response
  3. When the AI calls tools (file reads, bash commands, etc.), the spinner pauses and tool calls display inline with their arguments and results
  4. Once complete, the full response renders as Rich Markdown --- syntax-highlighted code blocks, tables, headers, lists, bold/italic, and more
  5. A context footer shows a color-coded progress bar, token usage, response size, elapsed time, and remaining headroom before auto-compact

The AI runs in an agentic loop: it can call tools, inspect results, call more tools, and continue reasoning --- up to 50 iterations per turn by default. Multiple tool calls in a single response execute in parallel for faster results. This means it can tackle multi-step tasks like "find and fix the bug in auth.py" or "add tests for the user service" autonomously, without you needing to intervene between steps.

Prompt queuing: You can type and submit messages while the AI is working. They queue (up to 10) and process in FIFO order when the current response finishes. The prompt stays active at the bottom of the terminal while output streams above it.

Welcome Banner

On startup, the REPL displays:

Parlor CLI - /path/to/your/project
  Model: gpt-4 | Tools: 6 | Instructions: loaded | Branch: main
  Type /help for commands, Ctrl+D to exit
  • Model: The active AI model from your config
  • Tools: Total count of available tools (built-in + MCP)
  • Instructions: Whether a PARLOR.md file was found and loaded
  • Branch: Current git branch (auto-detected, shown only inside a git repo)

Built-in Tools

Six tools ship out of the box (no MCP server required):

Tool What it does Key parameters
read_file Read file contents with line numbers path, offset (1-based start line), limit (max lines). Output truncated at 100KB.
write_file Create or overwrite files. Parent directories created automatically. path, content. Returns bytes written.
edit_file Exact string replacement. old_text must match exactly once (unique) or use replace_all=true. path, old_text, new_text, replace_all.
bash Run shell commands. Returns stdout, stderr, and exit code. command, timeout (default 120s, max 600s). Output truncated at 100KB.
glob_files Find files matching a glob pattern. Results sorted by modification time (newest first). pattern (e.g., **/*.py), path (search root). Max 500 results.
grep Regex search across files with context lines and file-type filtering. pattern, path, glob filter, context lines, case_insensitive. Max 200 matches, skips files over 5MB.

All file tools resolve paths relative to the working directory (or accept absolute paths). Every tool returns structured JSON that the AI uses to inform its next action.

Tool Safety

Two layers of protection prevent accidental damage:

Destructive command confirmation --- The following patterns in bash commands trigger an interactive Proceed? [y/N] prompt before execution:

rm, rmdir, git push --force, git push -f, git reset --hard, git clean, git checkout ., drop table, drop database, truncate, > /dev/, chmod 777, kill -9

Path and command blocking --- Hardcoded blocks that cannot be bypassed:

  • Blocked paths: /etc/shadow, /etc/passwd, /etc/sudoers, and anything under /proc/, /sys/, /dev/ (follows symlinks)
  • Blocked commands: rm -rf /, mkfs, dd if=/dev/zero, fork bombs
  • Null byte injection: Rejected in all paths, commands, and glob patterns

File References

Reference files and directories directly in your prompt with @:

you> explain @src/main.py
you> what tests cover @src/auth/
you> compare @old.py and @new.py
you> review @"path with spaces/file.py"
Syntax What it does
@file.py Inlines the full file contents wrapped in <file path="..."> tags (truncated at 100KB)
@directory/ Inlines a listing of directory contents wrapped in <directory> tags (up to 200 entries, with / suffix for subdirectories)
@"quoted path" Handles paths containing spaces (single or double quotes)

Paths are resolved relative to the working directory. Absolute paths are also supported. If a path doesn't exist, the @reference is left as-is in the prompt.

Thinking Spinner

While the AI generates a response, a Rich Status spinner (animated dots) displays on stderr with an elapsed timer that updates every second:

⠋ Thinking... (3s)

When the AI pauses to execute tool calls, the spinner stops and tool call output appears. The spinner resumes when the AI starts generating again. Total elapsed time accumulates across all thinking segments and is reported in the context footer.

Rich Markdown Rendering

Responses are buffered silently (no streaming flicker), then rendered in full using Rich's Markdown engine. This gives you:

  • Syntax-highlighted code blocks with language detection
  • Tables, headers, bold/italic, lists, blockquotes
  • Padded layout with breathing room (2-character indent on both sides)

Output goes to stdout (for piping/redirecting), while chrome (spinner, tool calls, context footer) goes to stderr.

Context Management

Parlor tracks token usage across the conversation using tiktoken (cl100k_base encoding) with a character-estimate fallback (1 token per 4 chars) when tiktoken is unavailable:

Threshold What happens
80,000 tokens Yellow warning: "Use /compact to free space"
100,000 tokens Auto-compact triggers automatically before the next prompt
128,000 tokens Effective context window ceiling

The context footer after each response shows:

  [====----------------] 12,340/128,000 tokens (10%) | response: 482 | 3.2s | 87,660 until auto-compact
  • Progress bar with color coding: green (<50%), yellow (50-75%), red (>75%)
  • Current token count / max context window
  • Response token count for the current turn
  • Total elapsed thinking time
  • Remaining tokens until auto-compact fires

Compact

/compact (or auto-compact at 100K tokens) sends the full conversation history to the AI with a summarization prompt. The AI generates a concise summary preserving:

  • Key decisions and conclusions
  • File paths that were read, written, or edited
  • Important code changes and their purpose
  • Current task state
  • Errors encountered and how they were resolved

Tool call outputs are truncated to 500 characters each in the summary prompt to keep it focused. After compacting, the message history is replaced with a single system message containing the summary. Token savings are reported:

  Compacted 47 messages -> 1 messages
  ~32,140 -> ~890 tokens

Minimum 4 messages required to compact (prevents compacting a nearly-empty conversation).

Conversation Management

Every conversation is persisted to SQLite. The REPL provides several ways to navigate them:

Command Behavior
/new Creates a new conversation and clears message history
/last Loads the most recent conversation (by creation time) with all its messages
/list Shows the 20 most recent conversations with title, message count, and truncated ID
/resume 3 Resume by list number (from /list output)
/resume a1b2c3d4... Resume by full conversation ID
Recent conversations:
  1. Fix auth middleware bug (12 msgs) a1b2c3d4...
  2. Add user settings page (8 msgs) e5f6a7b8...
  3. Refactor database layer (23 msgs) c9d0e1f2...
  Use /resume <number> or /resume <id>

On startup with -c, the most recent conversation is loaded automatically. With -r <id>, a specific conversation is loaded.

Auto-Title Generation

After the first exchange in a new conversation, Parlor sends your prompt to the AI to generate a short, descriptive title. This title appears in /list, the web UI sidebar, and is stored in the database. Titles are generated asynchronously and silently --- failures are ignored.

Model Switching

Switch models mid-session without restarting:

you> /model gpt-4-turbo
  Switched to model: gpt-4-turbo

you> /model
  Current model: gpt-4-turbo
  Usage: /model <model_name>

The new model applies to all subsequent turns in the current session. The conversation history carries over.

REPL Commands

Command Action
/new Start a new conversation
/last Resume the most recent conversation
/list Show 20 most recent conversations with message counts
/resume N Resume by list number or full conversation ID
/rewind Rewind to a previous message, optionally undoing file changes via git
/compact Summarize and compact message history to free context
/model NAME Switch to a different model mid-session (omit NAME to see current)
/tools List all available tools (built-in + MCP), sorted alphabetically
/skills List available skills with descriptions and source (default/global/project)
/help Show all commands, input syntax, and keyboard shortcuts
/quit, /exit Exit the REPL

Input & Prompt

The you> prompt is displayed in bright cyan bold for clear visual distinction from AI responses.

Multiline input: Enter submits your message. Alt+Enter inserts a newline. Continuation lines are indented to align under the prompt text.

Paste collapsing: When you paste more than 6 lines, the terminal display automatically collapses to show the first 3 lines plus ... (N more lines). The full content is still sent to the AI --- only the visual display is truncated to keep your terminal readable.

Keyboard Shortcuts

Shortcut Action
Enter Submit message
Alt+Enter Insert a newline (multiline input)
Escape Cancel the current AI response
Ctrl+C Clear current input. If input is empty, exit the REPL. During AI generation, also cancels.
Ctrl+D Exit the REPL (EOF)
Tab Autocomplete (see below)

Tab Completion

Tab completion works for three categories:

  • Commands: Type / then Tab to see all slash commands (/new, /list, /compact, etc.)
  • Skills: Type / then Tab to also see skill names (/commit, /review, /explain, and any custom skills)
  • File paths: Type @ then Tab to browse files and directories from the working directory. Subdirectories show with a / suffix. Hidden files (starting with .) are excluded. Supports nested path completion (@src/ then Tab).

Command History

Input history is persisted to ~/.parlor/cli_history using prompt_toolkit's FileHistory. Previous commands are available with the up/down arrow keys across sessions.

One-Shot Mode

Pass a prompt as an argument to run a single turn and exit:

parlor chat "list all Python files in src/"
parlor chat "explain the auth middleware"
parlor chat -c "now add rate limiting to it"    # Continue last conversation
parlor chat -r a1b2c3d4 "fix the failing test"  # Continue specific conversation

One-shot mode creates a conversation in the database (visible in the web UI), generates a title, and exits after the response completes. The AI still has access to all tools and can run multiple agentic iterations --- the "one-shot" refers to a single user turn, not a single AI action.

Skills

Skills are reusable prompt templates invoked with /name. Three ship by default:

Skill What it does
/commit Runs git diff, stages relevant files, creates a conventional commit (type(scope): description)
/review Reviews git diff for bugs, security issues, performance concerns, missing error handling, and missing tests. Returns structured findings with severity levels.
/explain Reads referenced code and explains architecture, data flow, components, and design patterns

Skill arguments: Append extra context after the skill name. It gets appended to the skill's prompt template:

you> /commit
you> /review just the auth changes
you> /explain @src/services/agent_loop.py focus on the event system

Custom skills: Add YAML files to ~/.parlor/skills/ (global) or .parlor/skills/ (per-project):

name: test
description: Run tests and fix failures
prompt: |
  Run the test suite. If any tests fail, read the failing test
  and the relevant source code, then fix the issue.
name: deploy
description: Build and deploy to staging
prompt: |
  1. Run the full test suite
  2. Build the production bundle
  3. Deploy to the staging environment
  4. Verify the deployment is healthy

Precedence: Project skills (.parlor/skills/) override global skills (~/.parlor/skills/), which override default built-in skills. Parlor walks up from the working directory to find the nearest .parlor/skills/ directory, similar to how PARLOR.md is discovered.

Project Instructions (PARLOR.md)

Create a PARLOR.md in your project root to inject context into every conversation:

# Project: my-app

## Tech Stack
- Python 3.12, FastAPI, SQLAlchemy
- PostgreSQL 16, Redis 7

## Conventions
- All functions must have type hints
- Use conventional commits
- Tests required for all new features

Discovery: Parlor walks up from the current working directory to find the nearest PARLOR.md. A global ~/.parlor/PARLOR.md applies to all projects. Both are loaded if found --- global instructions come first, then project-specific ones.

System prompt construction: The CLI builds a system prompt from three sources, concatenated in this order:

  1. Working directory context: "You are an AI coding assistant working in: /path/to/project" + tool usage guidance
  2. PARLOR.md instructions (global + project, if found)
  3. The system_prompt from config.yaml

Shared Database

CLI and web UI share the same SQLite database (~/.parlor/chat.db). Conversations created in the terminal show up in the web sidebar, and vice versa. Every user message, assistant response, and tool call is persisted with the same schema used by the web UI.

Titles are auto-generated after the first exchange. Tool calls are stored with their inputs and outputs, so the web UI can render expandable tool call panels for conversations that originated in the CLI.

Unified Tool Executor

Built-in tools and MCP tools work side by side. When the AI calls a tool:

  1. Built-in tools are checked first --- if the tool name matches a registered built-in (read_file, write_file, etc.), it executes locally with no network overhead
  2. MCP tools are checked second --- if no built-in matches, the call is forwarded to the appropriate MCP server

This means a single conversation can use read_file (built-in) and query_database (MCP) in the same agentic loop. Use /tools to see the full list of available tools from both sources.

Cross-Platform Support

The CLI works on macOS, Linux, and Windows:

  • Signal handling (Ctrl+C to cancel generation) uses asyncio.add_signal_handler on Unix and falls back gracefully on Windows where async signal handlers aren't supported
  • Path resolution uses os.path.realpath for consistent behavior across platforms
  • The prompt toolkit input handles platform-specific terminal differences

CLI Configuration

Add a cli: section to ~/.parlor/config.yaml:

cli:
  builtin_tools: true     # Enable built-in file/bash tools (default: true)
  max_tool_iterations: 50 # Max agentic loop iterations per response (default: 50)
  • builtin_tools: false disables all six built-in tools. MCP tools (if configured) still work. Same effect as --no-tools on the command line.
  • max_tool_iterations caps how many tool-call rounds the AI can make per turn. Set lower for simpler tasks, higher for complex multi-step operations.

MCP servers configured in the same config.yaml are available in both CLI and web UI.


Configuration

Config File

~/.parlor/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"     # bind address
  port: 8080             # server port
  data_dir: "~/.parlor" # where DB + attachments live
  tls: false             # set true for HTTPS with self-signed cert

# Optional: CLI settings
cli:
  builtin_tools: true     # Enable built-in tools (default: true)
  max_tool_iterations: 50 # Max tool calls per response (default: 50)

# 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"]
    env:
      API_KEY: "${MY_API_KEY}"

  - 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

Command Reference

parlor              Launch web UI server and open browser
parlor chat         Interactive CLI chat (agentic REPL)
parlor chat "msg"   One-shot mode (run prompt and exit)
parlor chat -c      Continue last conversation
parlor chat -r ID   Resume a specific conversation
parlor chat --no-tools  Disable built-in tools
parlor --test       Test connection, list models, send test prompt
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 everywhere, 0600 file permissions, path validation
Input Sanitization DOMPurify on all rendered HTML, UUID validation on all IDs, filename sanitization
Rate Limiting 120 req/min per IP with LRU eviction
Body Size 15 MB max request
CORS Locked to configured origin, explicit method/header allowlist
File Safety MIME type allowlist + magic-byte verification, path traversal prevention, forced download for non-images
MCP Safety SSRF protection with DNS resolution, shell metacharacter rejection in tool args
SRI SHA-384 hashes on all vendor scripts
API Surface OpenAPI/Swagger docs disabled
CLI Safety Destructive command confirmation, path validation blocks /etc/shadow, /proc/, etc.

Full details in SECURITY.md.


Data Storage

Everything stays on your machine. Nothing phones home.

~/.parlor/
  config.yaml          # Configuration          (permissions: 0600)
  chat.db              # SQLite + WAL journal   (permissions: 0600)
  cli_history           # REPL command history
  attachments/         # Files by conversation  (permissions: 0700)

The data directory is created with 0700 permissions (owner-only). Database files are created with 0600 permissions. WAL and SHM sidecar files are locked down too.


API Reference

Parlor exposes a full REST API. All endpoints require authentication via session cookie + CSRF token.

Conversations
Method Endpoint Description
GET /api/conversations List (with ?search=, ?project_id=, ?db=)
POST /api/conversations Create
GET /api/conversations/:id Get with messages, attachments, and tool calls
PATCH /api/conversations/:id Update title, folder, model
DELETE /api/conversations/:id Delete with all attachments
GET /api/conversations/:id/export Export as Markdown
POST /api/conversations/:id/chat Stream chat (SSE)
POST /api/conversations/:id/stop Cancel active generation
POST /api/conversations/:id/fork Fork at a message position
POST /api/conversations/:id/rewind Rewind to a position, optionally revert file changes
POST /api/conversations/:id/copy Copy to another database (?target_db=)
Messages & Attachments
Method Endpoint Description
PUT /api/messages/:id Edit message content (deletes subsequent messages)
DELETE /api/messages/:id Delete messages after a position
GET /api/attachments/:id Download attachment file
Projects
Method Endpoint Description
GET /api/projects List all projects
POST /api/projects Create project (name, instructions, model)
PATCH /api/projects/:id Update name, instructions, or model
DELETE /api/projects/:id Delete project (conversations preserved)
Folders
Method Endpoint Description
GET /api/folders List folders (?project_id= to filter)
POST /api/folders Create folder (name, parent_id, project_id)
PATCH /api/folders/:id Update name, parent, collapsed state, position
DELETE /api/folders/:id Delete folder + subfolders (conversations preserved)
Tags
Method Endpoint Description
GET /api/tags List all tags
POST /api/tags Create tag (name, color)
PATCH /api/tags/:id Update name or color
DELETE /api/tags/:id Delete tag (removed from all conversations)
POST /api/conversations/:id/tags/:tag_id Add tag to conversation
DELETE /api/conversations/:id/tags/:tag_id Remove tag from conversation
Databases
Method Endpoint Description
GET /api/databases List all connected databases
POST /api/databases Add database (name, path)
DELETE /api/databases/:name Remove database connection
GET /api/browse?path= Browse filesystem for .db/.sqlite/.sqlite3 files
Config & Models
Method Endpoint Description
GET /api/config Get current config + MCP server statuses
PATCH /api/config Update model and/or system prompt
POST /api/config/validate Test API connection, list models
GET /api/models List available models (sorted)
GET /api/mcp/tools List all available MCP tools with schemas

Development

git clone https://github.com/troylar/parlor.git
cd parlor
pip install -e ".[dev]"

pytest tests/ -v          # Run 343 tests
ruff check src/ tests/    # Lint
ruff format src/ tests/   # Format

Tech Stack

Backend Python 3.10+, FastAPI, Uvicorn
Frontend Vanilla JS (no build step), marked.js, highlight.js, KaTeX, DOMPurify
CLI Rich, prompt-toolkit, tiktoken
Database SQLite with FTS5 full-text search, WAL journaling
AI OpenAI Python SDK (async streaming)
MCP Model Context Protocol SDK (stdio + SSE transports)
Streaming Server-Sent Events (SSE)
Typography Inter + JetBrains Mono (self-hosted WOFF2, zero external requests)
Security OWASP ASVS L1 compliance, SRI, CSP, CSRF, rate limiting

MIT License
Built for people who care about their conversations.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

parlor-0.12.0.tar.gz (734.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

parlor-0.12.0-py3-none-any.whl (751.8 kB view details)

Uploaded Python 3

File details

Details for the file parlor-0.12.0.tar.gz.

File metadata

  • Download URL: parlor-0.12.0.tar.gz
  • Upload date:
  • Size: 734.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for parlor-0.12.0.tar.gz
Algorithm Hash digest
SHA256 0ef4bca47ab0a48432916896d1ff3938506c642ee3db6e25e7189e54ef46037b
MD5 b10b4c2487f490e79202db63559d416b
BLAKE2b-256 5840a9721e4c35f18bfa67911c7313e52083a57cca0809bee695c04803ff54cf

See more details on using hashes here.

File details

Details for the file parlor-0.12.0-py3-none-any.whl.

File metadata

  • Download URL: parlor-0.12.0-py3-none-any.whl
  • Upload date:
  • Size: 751.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for parlor-0.12.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7e895d122e783bd5fe2cf212c54b5fbd48e92e223641e4f61ff98dd3ecdcc23f
MD5 e9100ee17f64582712eb7208a1ee286e
BLAKE2b-256 6a1cbfc9e0175c1d3277a894eb2e57929a03fedf38f4caf61bc6348e6a64be70

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page