Replace outdated feature cards (v1.4-v1.13) with the latest additions: - Themes & accent colors (v1.20-v1.29) - Thinking/reasoning display (v1.18-v1.25) - Split view (v1.28) - Message search (v1.22) - Syntax highlighting input (v1.27) - Drag & drop sessions (v1.26) - Agent avatars (v1.19) - Raw JSON & metadata viewer (v1.15-v1.24) - Keyboard shortcuts (v1.13, kept)
PinchChat
A sleek, dark-themed webchat UI for OpenClaw — monitor sessions, stream responses, and inspect tool calls in real-time.
🎬 See the live demo → — interactive preview of the UI with tool call visualization, streaming, and more.
✨ Features
- 🔧 Tool call visualization — see what your agent is doing in real-time: colored badges, visible parameters, expandable results. The killer feature missing from every other chat UI.
- 💬 GPT-like interface — sessions in a sidebar, switch between conversations. Familiar if you've used ChatGPT or Claude.
- 📋 Multi-session navigation — browse all active sessions including cron jobs, sub-agents, and background tasks
- ⚡ Live streaming — watch the agent think and write token by token
- 📊 Token usage tracking — progress bars per session so you know how much context is left
- 🖼️ Inline images — generated or read images render directly in chat with lightbox preview
- 🎯 Chat-focused — no settings menus or config panels cluttering the screen. Just the conversation.
- 🎨 Themes — Dark, Light, and OLED Black modes with 6 accent colors. Persisted per-browser.
- 🧠 Thinking/reasoning display — see the agent's reasoning process in collapsible blocks with elapsed time
- 🔍 Message search — Ctrl+F to search and navigate through conversation history
- 📐 Split view — open 2 sessions side by side with a resizable divider
- ✍️ Syntax-highlighted input — real-time markdown coloring as you type (code blocks, bold, links)
- 🔀 Drag & drop reorder — organize sessions in the sidebar by dragging, order persists across reloads
- 📋 Raw JSON viewer — inspect full gateway message payloads for debugging
- 🗂️ Channel icons — Discord, Telegram, cron, and other session types shown with distinct icons
- 📤 Export conversations — download any session as a formatted Markdown file
- 🌐 i18n — English and French built-in, easy to extend
🚀 Quick Start
Docker (recommended)
docker run -p 3000:80 ghcr.io/marlburrow/pinchchat:latest
Open http://localhost:3000 and enter your OpenClaw gateway URL + token on the login screen.
Or use Docker Compose:
curl -O https://raw.githubusercontent.com/MarlBurroW/pinchchat/main/docker-compose.yml
docker compose up -d
From source
Prerequisites: Node.js 18+, an OpenClaw gateway running and accessible.
git clone https://github.com/MarlBurroW/pinchchat.git
cd pinchchat
npm install
cp .env.example .env
npm run dev
Optionally edit .env to pre-fill the gateway URL:
VITE_GATEWAY_WS_URL=ws://localhost:18789
VITE_LOCALE=en # or "fr" for French UI
Production build
npm run build
npx vite preview
Or serve the dist/ folder with nginx, Caddy, or any static file server.
⚙️ Configuration
All configuration is optional — credentials are entered at runtime via the login screen.
| Variable | Description | Default |
|---|---|---|
VITE_GATEWAY_WS_URL |
Pre-fill the gateway URL on the login screen | ws://<hostname>:18789 |
VITE_LOCALE |
UI language (en or fr) |
en |
Note: The gateway token is entered at runtime and stored in
localStorage— it is never baked into the build.
🏗 Architecture
graph TD
subgraph Browser["🌐 PinchChat (Browser)"]
Login["LoginScreen<br/><i>credentials</i>"]
App["App.tsx<br/><i>router</i>"]
UI["Chat + Sidebar<br/><i>main UI</i>"]
Hook["useGateway<br/><i>WebSocket state machine</i><br/>auth · sessions · messages"]
Login --> App --> UI
App & UI --> Hook
end
Hook <-->|"WebSocket (JSON frames)"| Gateway["🔌 OpenClaw Gateway<br/><code>ws://host:18789</code>"]
Gateway <-->|API| LLM["🤖 LLM Provider<br/><i>Anthropic, OpenAI, etc.</i>"]
Key Components
| File | Role |
|---|---|
src/hooks/useGateway.ts |
WebSocket connection, auth, message streaming, session management |
src/components/LoginScreen.tsx |
Runtime credential entry (stored in localStorage) |
src/components/Chat.tsx |
Message list with auto-scroll and streaming display |
src/components/ChatInput.tsx |
Input with file upload, paste, drag & drop, image compression |
src/components/ChatMessage.tsx |
Markdown rendering, tool calls, thinking blocks |
src/components/Sidebar.tsx |
Session list with token usage bars and activity indicators |
src/components/Header.tsx |
Connection status, token progress bar, logout |
src/lib/i18n.ts |
Lightweight i18n (English + French) |
src/lib/gateway.ts |
WebSocket protocol helpers and message types |
Data Flow
- Login — User enters gateway URL + token → stored in
localStorage - Connect —
useGatewayopens a WebSocket and authenticates with the token - Sessions — Gateway pushes session list; user selects one in the sidebar
- Messages — Messages stream in via WebSocket frames; the hook assembles partial chunks into complete messages
- Send — User input (+ optional file attachments) is sent as a JSON frame over the WebSocket
📖 For a deeper dive into the codebase structure, see ARCHITECTURE.md.
🌐 Adding a Language
PinchChat uses a zero-dependency i18n system. Adding a new language takes ~5 minutes:
- Open
src/lib/i18n.tsand duplicate theenobject with your locale code:
const de: typeof en = {
'login.title': 'PinchChat',
'login.subtitle': 'Verbinde dich mit deinem OpenClaw-Gateway',
// ... translate all keys
};
- Register it in the
messagesrecord (same file):
const messages: Record<string, typeof en> = { en, fr, de };
- Add a label for the language selector:
export const localeLabels: Record<string, string> = {
en: 'EN',
fr: 'FR',
de: 'DE',
};
- Done. The language selector,
VITE_LOCALE, and browser auto-detection all pick it up automatically.
Tip: TypeScript enforces that your new locale object has the same keys as
en— missing translations won't compile.
⌨️ Keyboard Shortcuts
Press ? anywhere to open the shortcuts panel.
| Shortcut | Action |
|---|---|
Enter |
Send message |
Shift + Enter |
New line |
Esc |
Stop generation / close sidebar |
Ctrl/⌘ + F |
Search messages in current session |
Ctrl/⌘ + K |
Focus session search |
Alt + ↑ / Alt + ↓ |
Switch between sessions |
? |
Show shortcuts help |
❓ Troubleshooting
Connection fails / "WebSocket error"
- Make sure your OpenClaw gateway is running and reachable from the browser
- Check the gateway URL format:
ws://host:18789(orwss://if behind TLS) - If PinchChat is served over HTTPS, the gateway must also use
wss://— browsers block mixed content - Verify the gateway token is correct (copy-paste from your OpenClaw config)
Blank screen after login
- Open your browser's developer console (F12) and check for errors
- Ensure the gateway is running a compatible version of OpenClaw (v0.24+)
- Try clearing
localStorage(Application tab → Storage → Clear site data) and logging in again
Messages don't appear / sessions empty
- The WebSocket may have disconnected silently — check the connection indicator in the header
- If the gateway was restarted, PinchChat reconnects automatically, but you may need to refresh once
- Verify the token has access to the sessions you expect
Docker: "port already in use"
# Check what's using port 3000
lsof -i :3000
# Use a different port
docker run -p 8080:80 ghcr.io/marlburrow/pinchchat:latest
Images not displaying
- Inline images require the gateway to send media as base64 data URLs or accessible HTTP URLs
- If images show as broken, the gateway may be behind a reverse proxy that strips large payloads — check proxy buffer settings
Build errors from source
# Ensure Node.js 18+
node --version
# Clean install
rm -rf node_modules package-lock.json
npm install
npm run build
🛠 Tech Stack
- React 19
- Vite 7
- Tailwind CSS v4
- Radix UI primitives
- highlight.js via rehype-highlight
- Lucide React icons
- react-markdown with GFM
📄 License
MIT © Nicolas Varrot
📋 Changelog
See CHANGELOG.md for a detailed history of changes.
🔒 Security
See SECURITY.md for the security policy and how to report vulnerabilities.
🤝 Contributing
Contributions are welcome! See CONTRIBUTING.md for guidelines.
🔗 Links
- OpenClaw — the AI agent platform PinchChat connects to

