<p align="center">
  <img src="public/pi.svg" width="80" height="80" alt="pi-switch logo" />
</p>

<h1 align="center">pi-web-switch</h1>

<p align="center">
  <strong>Web UI for pi coding agent — live configuration management, session browser, and memory viewer</strong>
</p>

<p align="center">
  <a href="README.md">🇬🇧 English</a> ·
  <a href="README.zh-CN.md">🇨🇳 中文</a> ·
  <a href="README.ja.md">🇯🇵 日本語</a>
</p>

<p align="center">
  <img src="https://img.shields.io/badge/React-19-61DAFB?logo=react" alt="React 19" />
  <img src="https://img.shields.io/badge/TypeScript-5.8-3178C6?logo=typescript" alt="TypeScript" />
  <img src="https://img.shields.io/badge/Tailwind-4-06B6D4?logo=tailwindcss" alt="Tailwind v4" />
  <img src="https://img.shields.io/badge/Vite-6-646CFF?logo=vite" alt="Vite 6" />
  <img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License" />
</p>

<p align="center">
  Inspired by <a href="https://github.com/farion1231/cc-switch">cc-switch</a> — a visual dashboard for managing your <a href="https://pi.dev">pi coding agent</a> providers, models, token usage, sessions, and settings.
</p>

<p align="center">
  <strong>Reads data directly from <code>~/.pi/agent/</code></strong> — no mock data, no database, no backend setup required.
</p>

---

## ✨ Features

### 📊 Dashboard
- **Usage Statistics** — All time / Today / 7 days / 30 days / Custom date range selector with auto-refresh (5s/10s/30s/60s)
- **All Sources Overview** — Combine all locally supported usage sources in one dashboard, while keeping Pi and ChatGPT/Codex views available separately
- **Token Breakdown** — Exact token count with approximate display (e.g. `1,631,022 ≈ 1.6M`) and Input/Output/Cache Hit/Cache Create breakdown
- **Cost Tracking** — Daily cost chart + Provider/Model stats tabs with aggregated data
- **Cache Hit Rate** — Visual progress bar showing cache efficiency
- **Request Log** — Detailed log table with time, provider, model, tokens, cost
- **Currency Switch** — Toggle between USD and CNY with real-time conversion (1 USD = 7.2 CNY)
- **Hourly/Daily Granularity** — Today view shows per-hour data; 7d/30d views show per-day data
- All data sourced from **real pi session files** (`~/.pi/agent/sessions/*.jsonl`)

### 📦 Models
- **Model Grid** — Browse all built-in and custom models with search and filter
- **Enable/Disable** — Toggle models on/off to match your `enabledModels` config
- **Edit Model** — Update capabilities, cost, context window, max tokens
- **Add Model** — Create new models for any provider
- **Delete Model** — Remove custom models

### 🔌 Providers
- **Provider List** — Expandable cards for all built-in and custom providers
- **Custom Providers** — Add Ollama, vLLM, LM Studio, or any OpenAI-compatible provider
- **API Key Management** — Set/remove API keys per provider (saved to `auth.json`)
- **Provider Configuration** — baseUrl, API type, custom headers, auth method
- **Enabled Models Panel** — Cross-provider list of every enabled model with one-click disable / disable-all, kept in sync with each provider's per-model toggles
- **Fetch Models Online** — Pull a provider's live model list from its `/models` endpoint and import with one click

### 💬 Sessions
- **Project Grouping** — Auto-decodes session directory names into project paths
- **Session Browser** — View all 100+ sessions across projects
- **Session Details** — Name, timestamp, message count, duration, provider/model used
- **Search & Filter** — Filter sessions by project name
- **Delete Sessions** — Remove old session files (sessions updated within 3 days are protected)

### 🧠 Memory (pi-hermes-memory)
- **Project Memories** — View `MEMORY.md` content with Markdown rendering
- **User Profile** — Display `USER.md` preferences and settings
- **Failure Records** — Browse `failures.md` known issues
- **Live Sync** — Content updates immediately when memory files change on disk

### 🌐 Multi-language
- **English** 🇬🇧 — Default
- **Simplified Chinese** 🇨🇳 — 简体中文
- **Traditional Chinese** 🇭🇰 — 繁體中文
- **Japanese** 🇯🇵 — 日本語
- Language switcher in sidebar footer, persists across sessions

### ⚙️ Settings
- **Defaults** — Default provider, model, thinking level, project trust
- **Theme** — Light / Dark / System with immediate toggle (CSS variables for both modes)
- **Interface Zoom** — Scale the entire UI by percentage (50%–200%), plus a font-size slider
- **Extensions & Packages** — Manage pi packages list
- **Import/Export** — Download full config as JSON, restore from backup
- **Reset** — Factory reset to blank configuration

### 🖥️ Native macOS Menu Bar
- **Two Lightweight Apps** — Separate Swift/AppKit menu bar apps for Pi usage and ChatGPT/Codex usage, with no Electron, WebView, or resident web server
- **Pi Usage App** — Pi today/7-day usage, cost, cache rate, and provider totals
- **ChatGPT Usage App** — Local ChatGPT/Codex session usage and official Codex quota
- **Background Refresh** — Reads local session files and refreshes quota data without blocking the menu bar
- **Separate Visibility Controls** — The Settings page controls each menu bar app through `~/.pi/agent/settings.json`

macOS and Swift Command Line Tools are required. From a checkout of this repository:

```bash
npm run native:build  # Build both .app bundles under release/
npm run native:open   # Build and launch both menu bar apps
```

## 🌗 Theme Support

Full light and dark mode with system-follow support. Theme toggles instantly via CSS custom properties — no page reload needed. All components adapt including sidebar, modals, forms, charts, and scrollbars.

## 🧱 Built-in Providers

The built-in catalog is read **live from your local pi installation** — the same data pi ships and [pi.dev/models](https://pi.dev/models) lists (`@earendil-works/pi-ai/dist/providers/data/*.json`). Upgrading pi upgrades this panel; with pi `0.85.1` that is **37 providers and 1,153 models**, 733 of which accept image input. Results are cached for 5 minutes and refreshed when the dev server restarts.

When no pi install can be located (e.g. a fresh checkout), the app falls back to a small hand-maintained catalog in `src/data/builtin-providers.ts` — 10 providers / 38 models covering Anthropic, OpenAI, DeepSeek, Google, OpenCode Zen (+ Go), OpenRouter, Mistral, GitHub Copilot and Groq.

Models you add or import are written to `~/.pi/agent/models.json` and merged over the catalog: an entry whose id matches a built-in provider (e.g. `mistral`) augments that provider instead of appearing as a duplicate, and a display name you set there wins over the catalog name.

## 🚀 Getting Started

### Prerequisites

- **pi coding agent** installed and configured (so `~/.pi/agent/` exists)
- Node.js 18+

### Setup

```bash
# Clone
git clone https://github.com/Raingor/pi-web-switch.git
cd pi-web-switch

# Install dependencies
npm install

# Start dev server (reads ~/.pi/agent/ automatically)
npm run dev

# Build for production
npm run build

# Preview production build
npm run preview
```

The dev server automatically serves pi configuration via Vite middleware at `/api/pi/*` — no separate backend process needed.

## 🖥️ Sister Project — pi-of-cindy

pi-web-switch runs in the browser. If you want a more complete **desktop, mobile, and AI agent workbench**, see its sister project:

> **[pi-of-cindy](https://github.com/Raingor/pi-of-cindy)** — a pi-only rework of the CINDY client, including an Electron desktop app, an Expo / React Native mobile app, and shared packages.
> It uses the local [pi](https://github.com/earendil-works/pi) CLI as its sole workbench, with Pi providers, dashboard, tasks, memory, subagents, and local session import. It shares `~/.pi/agent/` with the local pi CLI.
>
> Key capabilities of pi-of-cindy:
> - **Multi-platform agent workbench** — desktop, mobile, and shared capabilities in one pnpm monorepo
> - **Harness × model composition** — supports Agent Harnesses such as Claude Code and Codex, with planning, parallel execution, and independent review
> - **Real-environment execution** — can operate browsers, computers, and phones using local files and logged-in apps
> - **Pi-only local workflow** — imported pi CLI sessions can continue directly, with providers and models kept in sync with the terminal
> - **Apache-2.0 open source** — build and extend the client yourself
>
> See the **[pi-of-cindy README](https://github.com/Raingor/pi-of-cindy)** for downloads and complete documentation.

**Both share the local `~/.pi/agent/` config**, so providers, models, and memories changed in either project remain available to the other and to the terminal `pi`.

| | pi-web-switch (this project) | pi-of-cindy |
|---|---|---|
| Form | Browser panel (Vite dev server) | Electron desktop app + Expo / React Native mobile app |
| Focus | Configuration management — Dashboard / Providers / Sessions / Memory side by side | Multi-platform AI agent workbench — task execution, harness orchestration, and local sessions |
| Pi integration | Pi package / local configuration panel | Local pi CLI as the core, sharing `~/.pi/agent/` |
| License | MIT | Apache-2.0 |
| Development | `npm run dev` | `pnpm install` + `pnpm restart:desktop:remote` |

## 🏗️ Tech Stack

| Layer | Technology |
|-------|-----------|
| Framework | [React 19](https://react.dev/) |
| Language | [TypeScript 5.8](https://www.typescriptlang.org/) |
| Build | [Vite 6](https://vitejs.dev/) |
| Styling | [Tailwind CSS v4](https://tailwindcss.com/) |
| State | [Zustand](https://github.com/pmndrs/zustand) |
| Charts | [Recharts](https://recharts.org/) |
| Icons | [Lucide React](https://lucide.dev/) |
| Routing | [React Router v7](https://reactrouter.com/) |

## 🗂️ Project Structure

```
pi-web-switch/
├── index.html
├── package.json
├── vite.config.ts          # Vite config + pi API plugin (middleware)
├── tsconfig.json
├── server/
│   └── pi-reader.ts        # Server-side module: reads ~/.pi/agent/ files + parses sessions
├── native/
│   ├── NativeUsageSupport.swift # Shared usage readers and formatters
│   ├── PiUsageMenuBar.swift # Pi usage menu bar app
│   └── ChatGPTUsageMenuBar.swift # ChatGPT/Codex usage menu bar app
├── scripts/
│   └── build-native-menubar.sh
├── pi-package/
│   ├── index.ts            # Extension entry: /pi-switch and /pi-usage commands
│   └── skills/
├── public/
│   └── pi.svg
└── src/
    ├── main.tsx            # Entry point + theme sync + init gate + i18n provider
    ├── App.tsx             # Router setup
    ├── index.css           # Tailwind + CSS theme variables (light/dark)
    ├── types/index.ts      # All TypeScript interfaces
    ├── data/
    │   ├── builtin-providers.ts   # Static built-in provider fallback catalog
    │   ├── model-catalog.ts       # Smart model catalog + metadata autofill
    │   └── changelog.ts           # Version changelog for the "What's new" dialog
    ├── store/
    │   └── config-store.ts # Zustand store (fetches from /api/pi/*)
    ├── hooks/
    │   └── useSessionUsage.ts     # Live session token/cost polling
    ├── lib/
    │   ├── utils.ts        # Formatting helpers (tokens, cost with USD/CNY)
    │   ├── i18n.tsx        # Multi-language system (React Context + hook)
    │   ├── currency.ts     # Currency switching (USD/CNY toggle)
    │   ├── config.ts       # Config import/export helpers
    │   ├── pi-settings.ts  # Nested settings merge (keeps sibling CLI values)
    │   ├── models-json.ts  # models.json payload builders (keeps disabled providers)
    │   ├── provider-import.ts     # Freeform provider/key-pool import parser
    │   └── translations/   # Translation files (en, zh-CN, zh-TW, ja)
    └── components/
        ├── layout/          # AppShell, BasicSidebar (nav + language switcher)
        ├── ui/              # StatCard, Badge, Modal, EmptyState
        ├── help/            # HelpButton, ChangelogButton
        ├── dashboard/       # DashboardPage + charts (hourly/daily granularity)
        ├── generate/        # GeneratePage (image / video generation)
        ├── providers/       # ProvidersModelsPage + forms
        ├── speedtest/       # ModelSpeedTestPage
        ├── subagents/       # SubagentsPage (agents, chains, run history)
        ├── sessions/        # SessionsPage + MemoryPage
        └── settings/        # SettingsPage, PiCliSettingsPage, SkillsPage, CommandsPage
```

## 💾 Data Source

All data is read directly from **`~/.pi/agent/`** on your machine via a Vite middleware API plugin — no mock data, no database, no external service.

| File | Purpose |
|------|---------|
| `~/.pi/agent/settings.json` | Default provider, model, theme, enabled models, packages |
| `~/.pi/agent/auth.json` | API keys per provider |
| `~/.pi/agent/models.json` | Custom provider definitions (baseUrl, API type, models) |
| `~/.pi/agent/sessions/*.jsonl` | Session history with token usage, model, provider per message |
| `~/.pi/agent/pi-hermes-memory/*.md` | Hermes memory (MEMORY.md, USER.md, failures.md) |
| local pi install (`@earendil-works/pi-ai`) | Built-in provider & model catalog — read-only |

Changes made in the UI are written back to these files in real time — the pi agent picks them up on next reload.

### Sessions & Usage

- The app parses **106+ JSONL session files** from `sessions/` directory
- Each assistant message's API usage data (tokens, cost) is extracted and aggregated
- Dashboard shows real token consumption, costs, and request volumes across all sessions
- Sessions list groups by project (decoded from directory names) with 24+ project groups

## 🧩 API Routes

These endpoints at `/api/pi/*` are served by the Vite middleware, so the frontend talks to your local pi install with no separate backend process:

| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/pi/settings` | Read `settings.json` |
| POST | `/api/pi/settings` | Write `settings.json` |
| GET | `/api/pi/auth` | Read `auth.json` |
| POST | `/api/pi/auth` | Write `auth.json` |
| GET | `/api/pi/models` | Read `models.json` |
| POST | `/api/pi/models` | Write `models.json` |
| GET | `/api/pi/builtin-providers` | Built-in provider + model catalog, read from the local pi install (static fallback if absent) |
| GET | `/api/pi/usage` | Aggregated token/cost/request data from sessions |
| GET | `/api/pi/usage-range` | Date-range filtered usage (pi sessions) — `?range=all\|today\|7d\|30d\|custom&from=&to=` |
| GET | `/api/pi/all-usage-range` | Same shape, but combined across **all** local sources (pi + cindy + claude + codex + ChatGPT/Codex Desktop + atomcode + copilot) |
| GET | `/api/pi/{cindy-pi\|claude\|codex\|opencode\|gemini\|grok\|atomcode\|copilot}-usage-range` | Per-source usage range |
| GET | `/api/pi/copilot-usage-range` | Local Copilot CLI usage from `~/.copilot/session-store.db` (tokens / requests per day per model; no GitHub API or token required) |
| GET | `/api/pi/copilot-config` | Read Copilot GitHub config (username, token) |
| POST | `/api/pi/copilot-config` | Write Copilot GitHub config |
| GET | `/api/pi/sessions` | Session list grouped by project |
| DELETE | `/api/pi/session?path=` | Move a session file to trash (path must be under sessions/) |
| POST | `/api/pi/session/trash` | Move a session to trash (body: `{ path }`) |
| POST | `/api/pi/session/restore` | Restore a session from trash (body: `{ trashPath }`) |
| GET | `/api/pi/session-preview` | Preview session messages — `?path=` |
| GET | `/api/pi/trash` | List trashed sessions |
| DELETE | `/api/pi/trash?path=` | Permanently delete a trashed session |
| GET | `/api/pi/memory` | Read MEMORY.md, USER.md, failures.md |
| POST | `/api/pi/memory/delete-entry` | Delete a memory entry (body: `{ filename, text }`) |
| GET | `/api/pi/subagents` | Read subagent run history |
| GET | `/api/pi/check-updates` | Check pi package updates |
| POST | `/api/pi/apply-updates` | Apply package updates (body: `{ names }`) |
| POST | `/api/pi/provider-test` | Test a provider connection (body: `{ baseUrl, apiKey }`) |
| POST | `/api/pi/provider-models` | Fetch a provider's live model list (body: `{ baseUrl, apiKey, providerId }`) |
| POST | `/api/pi/model-test` | Test a model (body: `{ baseUrl, modelId, apiKey, apiType }`) |

All `-usage-range` endpoints accept `&refresh=1` to force a rescan, bypassing the 30-second session cache (the Dashboard refresh button sends this).

## 📦 Pi Package

pi-web-switch can be installed as a **pi coding agent extension**, allowing you to start/stop the dashboard directly from your pi session.

### Install

Add `npm:pi-web-switch` to your `~/.pi/agent/settings.json` packages list:

```json
{
  "packages": ["npm:pi-web-switch"]
}
```

Or use the Settings page in the dashboard to add it.

### Commands

Once installed, the following commands are available in your pi session:

| Command | Description |
|---------|-------------|
| `/pi-switch start` | Launch the dashboard at `http://localhost:5173` |
| `/pi-switch stop` | Stop the server |
| `/pi-switch status` | Check if the dashboard is running |
| `/pi-usage` | Print a quick usage summary (today + 7 days) in the terminal — tokens / cost / requests / daily sparkline, without launching the dashboard |

The `/pi-usage` command reads `~/.pi/agent/sessions/*.jsonl` directly and aggregates today + last-7-days stats, so you can see your usage at a glance from any pi session.

### Package Structure

```
pi-web-switch/
├── package.json           # npm package with pi.extensions + pi.skills
├── pi-package/
│   ├── index.ts           # Extension entry: registers /pi-web-switch command
│   └── skills/
│       └── pi-web-switch/
│           └── SKILL.md   # Usage documentation
├── server/
│   └── pi-reader.ts       # Server-side: reads ~/.pi/agent/ files
└── src/                   # React frontend
```

## 💬 Community

Join the **Telegram group** for questions, suggestions, and bug reports:

👉 **[Join the pi-web-switch Telegram group](https://t.me/+ODpy7_7NlOE4NzA1)**

When reporting an issue, please include:

1. Your OS (macOS / Windows / Linux)
2. Your version — `npm view @raingor/pi-web-switch version`
3. A clear description plus any error screenshots or logs

## 🔗 Links

- **Sister project (CINDY pi-only client):** [github.com/Raingor/pi-of-cindy](https://github.com/Raingor/pi-of-cindy)
- **Homepage:** [raingor.github.io/my-blog](https://raingor.github.io/my-blog/)
- **GitHub:** [github.com/Raingor](https://github.com/Raingor)

## 📄 License

MIT
