PinchChat

PinchChat

[![CI](https://github.com/MarlBurroW/pinchchat/actions/workflows/ci.yml/badge.svg)](https://github.com/MarlBurroW/pinchchat/actions/workflows/ci.yml) [![GitHub Release](https://img.shields.io/github/v/release/MarlBurroW/pinchchat?color=cyan)](https://github.com/MarlBurroW/pinchchat/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen-brightgreen)](https://nodejs.org/) [![Docker](https://img.shields.io/badge/docker-ghcr.io-blue)](https://github.com/MarlBurroW/pinchchat/pkgs/container/pinchchat) [![GitHub Stars](https://img.shields.io/github/stars/MarlBurroW/pinchchat?style=social)](https://github.com/MarlBurroW/pinchchat) [![Website](https://img.shields.io/badge/website-GitHub%20Pages-blueviolet)](https://marlburrow.github.io/pinchchat/) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md) **A sleek, dark-themed webchat UI for [OpenClaw](https://github.com/openclaw/openclaw) โ€” monitor sessions, stream responses, and inspect tool calls in real-time.** > ๐ŸŽฌ **[See the live demo โ†’](https://marlburrow.github.io/pinchchat/)** โ€” interactive preview of the UI with tool call visualization, streaming, and more.

PinchChat Screenshot

## โœจ 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 - ๐Ÿ”” **Notification sounds** โ€” subtle audio chime for new messages (toggleable) - โŒจ๏ธ **Keyboard shortcuts** โ€” navigate sessions, toggle sidebar, search, and more without touching the mouse - ๐Ÿ“ฑ **PWA support** โ€” installable as a progressive web app with offline caching and auto-updates - โ™ฟ **Accessible** โ€” skip-to-chat link, focus-visible outlines, semantic HTML, `prefers-reduced-motion` support, ARIA live regions ## ๐Ÿš€ Quick Start ### Docker (recommended) ```bash 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: ```bash curl -O https://raw.githubusercontent.com/MarlBurroW/pinchchat/main/docker-compose.yml docker compose up -d ``` ### From source **Prerequisites:** Node.js 20+, an OpenClaw gateway running and accessible. ```bash 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: ```env VITE_GATEWAY_WS_URL=ws://localhost:18789 VITE_LOCALE=en # or "fr" for French UI ``` ### Production build ```bash 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://: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. ## ๐ŸŽจ Customization PinchChat stores all preferences in `localStorage` โ€” no server-side config needed. ### Themes Click the palette icon in the header to switch between: | Theme | Description | |-------|-------------| | **Dark** (default) | Zinc-based dark theme, easy on the eyes | | **Light** | Clean light mode with white backgrounds | | **OLED** | Pure black backgrounds for OLED screens | | **System** | Follows your OS dark/light preference | ### Accent Colors Six accent colors are available: **Cyan** (default), **Violet**, **Emerald**, **Amber**, **Rose**, and **Blue**. The accent tints buttons, links, progress bars, and user message bubbles. ### Other Preferences These settings persist across sessions: - **Sidebar width** โ€” drag the right edge to resize - **Session order** โ€” drag & drop to reorder; pinned sessions stay on top - **Syntax highlighting** โ€” toggle the `` button in the input area - **Split view** โ€” open two sessions side by side (icon in header) - **Language** โ€” switch between English and French via the globe icon - **Message drafts** โ€” input text is preserved per-session when switching ## ๐Ÿ— Architecture ```mermaid graph TD subgraph Browser["๐ŸŒ PinchChat (Browser)"] Login["LoginScreen
credentials"] App["App.tsx
router"] UI["Chat + Sidebar
main UI"] Hook["useGateway
WebSocket state machine
auth ยท sessions ยท messages"] Login --> App --> UI App & UI --> Hook end Hook <-->|"WebSocket (JSON frames)"| Gateway["๐Ÿ”Œ OpenClaw Gateway
ws://host:18789"] Gateway <-->|API| LLM["๐Ÿค– LLM Provider
Anthropic, OpenAI, etc."] ``` ### 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 1. **Login** โ€” User enters gateway URL + token โ†’ stored in `localStorage` 2. **Connect** โ€” `useGateway` opens a WebSocket and authenticates with the token 3. **Sessions** โ€” Gateway pushes session list; user selects one in the sidebar 4. **Messages** โ€” Messages stream in via WebSocket frames; the hook assembles partial chunks into complete messages 5. **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](ARCHITECTURE.md). ## ๐ŸŒ Adding a Language PinchChat uses a zero-dependency i18n system. Adding a new language takes ~5 minutes: 1. **Open `src/lib/i18n.ts`** and duplicate the `en` object with your locale code: ```ts const de: typeof en = { 'login.title': 'PinchChat', 'login.subtitle': 'Verbinde dich mit deinem OpenClaw-Gateway', // ... translate all keys }; ``` 2. **Register it** in the `messages` record (same file): ```ts const messages: Record = { en, fr, de }; ``` 3. **Add a label** for the language selector: ```ts export const localeLabels: Record = { en: 'EN', fr: 'FR', de: 'DE', }; ``` 4. **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` (or `wss://` 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" ```bash # 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 ### Debugging PinchChat includes built-in debugging tools: **WebSocket debug logging** โ€” open the browser console (F12) and run: ```js localStorage.setItem('pinchchat:debug', '1'); ``` Reload the page. All WebSocket frames (sent and received) will be logged to the console with a `[GW]` prefix. Set to `'0'` to disable. **Raw JSON viewer** โ€” click the `{ }` toggle on any message to see the full gateway payload as formatted JSON. Useful for understanding the protocol or reporting bugs. **Metadata inspector** โ€” hover over any message and click the โ„น๏ธ icon to see message metadata (timestamp, ID, channel, sender info). ### Build errors from source ```bash # Ensure Node.js 20+ node --version # Clean install rm -rf node_modules package-lock.json npm install npm run build ``` ## ๐Ÿ”€ Reverse Proxy PinchChat is a static SPA โ€” serve it behind any reverse proxy. The only special requirement is WebSocket support for the OpenClaw gateway connection. > **Note:** PinchChat itself only serves static files (HTML/JS/CSS). The WebSocket connection goes directly from the **browser** to your OpenClaw gateway, not through PinchChat's server. You only need to proxy WebSocket if you're also putting the gateway behind the same reverse proxy. ### Nginx ```nginx server { listen 443 ssl; server_name chat.example.com; # PinchChat static files location / { proxy_pass http://127.0.0.1:3000; # Or serve directly from the build output: # root /path/to/pinchchat/dist; # try_files $uri $uri/ /index.html; } } # Optional: proxy the OpenClaw gateway too server { listen 443 ssl; server_name gw.example.com; location / { proxy_pass http://127.0.0.1:18789; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_read_timeout 86400s; # Keep WebSocket alive } } ``` ### Caddy ```caddyfile chat.example.com { reverse_proxy 127.0.0.1:3000 } # Optional: proxy the gateway gw.example.com { reverse_proxy 127.0.0.1:18789 } ``` Caddy handles WebSocket upgrades and TLS automatically. ### Traefik (Docker labels) ```yaml services: pinchchat: image: ghcr.io/marlburrow/pinchchat:latest labels: - "traefik.enable=true" - "traefik.http.routers.pinchchat.rule=Host(`chat.example.com`)" - "traefik.http.routers.pinchchat.tls.certresolver=letsencrypt" - "traefik.http.services.pinchchat.loadbalancer.server.port=80" ``` ### Traefik (Kubernetes IngressRoute) ```yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: pinchchat spec: entryPoints: [websecure] routes: - match: Host(`chat.example.com`) kind: Rule services: - name: pinchchat port: 80 tls: certResolver: letsencrypt ``` ### Important notes - **HTTPS + WSS**: If PinchChat is served over HTTPS, the gateway URL must use `wss://` โ€” browsers block mixed content (`https` page โ†’ `ws://` connection) - **Timeouts**: Set generous read timeouts for the gateway proxy (WebSocket connections are long-lived). Nginx defaults to 60s which will drop the connection. - **Buffering**: If images aren't loading, increase proxy buffer sizes (`proxy_buffer_size`, `proxy_buffers` in Nginx) - **Health checks**: The PinchChat container responds to `GET /` with the SPA โ€” use it as a health check endpoint ## ๐Ÿ›  Tech Stack - [React](https://react.dev/) 19 - [Vite](https://vite.dev/) 7 - [Tailwind CSS](https://tailwindcss.com/) v4 - [Radix UI](https://www.radix-ui.com/) primitives - [highlight.js](https://highlightjs.org/) via rehype-highlight - [Lucide React](https://lucide.dev/) icons - [react-markdown](https://github.com/remarkjs/react-markdown) with GFM ## ๐Ÿ“„ License [MIT](LICENSE) ยฉ Nicolas Varrot ## ๐Ÿ“‹ Changelog See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes. ## ๐Ÿ”’ Security See [SECURITY.md](SECURITY.md) for the security policy and how to report vulnerabilities. ## ๐Ÿค Contributing Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. ## ๐Ÿ”— Links - [OpenClaw](https://github.com/openclaw/openclaw) โ€” the AI agent platform PinchChat connects to