diff --git a/.gitignore b/.gitignore
index d9ac13c..e7ab7f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@ node_modules/
dist/
.vite/
.DS_Store
-*.log
\ No newline at end of file
+*.log
+__pycache__/
\ No newline at end of file
diff --git a/README.md b/README.md
index ff4873b..d3a7d6f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
**A desktop workbench for the Pi coding agent.**
**Workspace-first, not chat-first.**
@@ -16,19 +16,25 @@
## Why this exists
-Daily coding-agent work means juggling repos, branches, and sessions, and the current tools are chat-first: the primary screen is a conversation, not your work. OpenPi flips that. It is a kitchen bench where every active repo, its branch, its sessions, and what has gone stale are visible at a glance.
+Daily coding-agent work means juggling repos, branches, and sessions, and the current tools are chat-first: the primary screen is a conversation, not your work. pidex flips that. It is a kitchen bench where every active repo, its branch, its sessions, and what has gone stale are visible at a glance.
-| The pain, observed daily | OpenPi's answer |
+| The pain, observed daily | pidex's answer |
|---|---|
| Workspace switching takes too many clicks | One dashboard of every repo with Pi sessions, sorted by last activity |
| Losing the thread when resuming | Repo, branch, and session state as first-class UI, not buried chat history |
| Long sessions get sluggish | [Pretext](https://github.com/chenglou/pretext) measures multiline text off the DOM hot path, ~600x faster than browser measurement |
| Worktrees feel unreliable | Git and worktree state surfaced directly, no chatting with the agent to switch branches |
-OpenPi is a personal project: learn by building, sharpen day-to-day DX, and share a cleaner local-first harness pattern for coding agents. Not a commercial product, not an OpenCode clone. Install, BYOK, and provider wiring belong to its sibling, Weldable; OpenPi focuses entirely on the daily coding workflow.
+pidex is a personal project: learn by building, sharpen day-to-day DX, and share a cleaner local-first harness pattern for coding agents. Not a commercial product, not an OpenCode clone. Install, BYOK, and provider wiring belong to its sibling, Weldable; pidex focuses entirely on the daily coding workflow.
> A developer's kitchen bench, not a chat pane.
+
+
+
+
+
+
## Quick Start
You need [mise](https://mise.jdx.dev/) and the [Pi CLI](https://pi.dev/). The dashboard reads existing sessions from `~/.pi/agent/sessions`, so run `pi` in a repo or two first if you want it to light up.
@@ -128,6 +134,33 @@ Long term:
- [ ] Task tracker awareness alongside sessions
- [ ] Optional adapters for other agent runtimes
+## Design tokens
+
+The workbench inherits its palette from the [Pi coding agent](https://pi.dev) so the desktop harness feels like part of the same family as the runtime it drives. Source of truth: [`scripts/_design.py`](scripts/_design.py), hexes pulled from `pi.dev/style.css`.
+
+| Token | Hex | Role |
+|---|---|---|
+| warm-black | `#13110f` | Primary window background |
+| bg-deep | `#0d1116` | Deepest surface |
+| bg-canvas | `#161d27` | Canvas surface |
+| panel | `#212730` | Sidebar / panel surface |
+| panel-soft | `#252f3d` | Card surface |
+| parchment | `#dacbc2` | Named cream, primary mark and text |
+| moonstone | `#ebe7e4` | Lighter cream, lit facet |
+| driftwood | `#5c5752` | Warm mid-gray, shadow facet |
+| terracotta | `#844f3b` | Warm bronze accent |
+| terracotta-light | `#b86b52` | Accent highlight, status dots |
+| sunkissed | `#e1b06e` | Warm gold accent |
+| sage | `#a3a473` | Sage accent |
+| accent-blue | `#6a9fcc` | Links, focus rings |
+
+Regenerate assets after a token edit:
+
+```bash
+uv run --with fonttools python scripts/build-icon.py # assets/icon, mark
+uv run --with fonttools python scripts/build-screenshot.py # docs/assets/screenshot
+```
+
## Documentation
| Doc | What it covers |
diff --git a/assets/icon-premium.jpg b/assets/icon-premium.jpg
new file mode 100644
index 0000000..3e1d497
Binary files /dev/null and b/assets/icon-premium.jpg differ
diff --git a/assets/icon.png b/assets/icon.png
new file mode 100644
index 0000000..1bc6600
Binary files /dev/null and b/assets/icon.png differ
diff --git a/assets/icon.svg b/assets/icon.svg
new file mode 100644
index 0000000..f86a3dc
--- /dev/null
+++ b/assets/icon.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/mark.png b/assets/mark.png
new file mode 100644
index 0000000..2c5b599
Binary files /dev/null and b/assets/mark.png differ
diff --git a/assets/mark.svg b/assets/mark.svg
new file mode 100644
index 0000000..7101342
--- /dev/null
+++ b/assets/mark.svg
@@ -0,0 +1,5 @@
+
diff --git a/docs/assets/banner.png b/docs/assets/banner.png
index 0a9c32f..4328c9a 100644
Binary files a/docs/assets/banner.png and b/docs/assets/banner.png differ
diff --git a/docs/assets/screenshot.png b/docs/assets/screenshot.png
new file mode 100644
index 0000000..c23b4cf
Binary files /dev/null and b/docs/assets/screenshot.png differ
diff --git a/docs/assets/screenshot.svg b/docs/assets/screenshot.svg
new file mode 100644
index 0000000..7ec5d0f
--- /dev/null
+++ b/docs/assets/screenshot.svg
@@ -0,0 +1,42 @@
+
diff --git a/scripts/_design.py b/scripts/_design.py
new file mode 100644
index 0000000..fe0b2cc
--- /dev/null
+++ b/scripts/_design.py
@@ -0,0 +1,73 @@
+"""Design tokens for pidex, sourced from the Pi coding agent website
+(pi.dev/style.css) so the workbench visually aligns with the Pi runtime
+it drives.
+
+Provenance: https://pi.dev/style.css, lines ~85-130 (the `:root` token
+block). Update these hexes if pi.dev revs its palette.
+
+Token groups:
+ - Warm darks (window bg, panel surfaces)
+ - Creams (text, marks, lit facet)
+ - Terracotta / sunkissed (warm accents, the fluid-crest peak)
+ - Sage / accent-blue (secondary accents)
+"""
+
+from __future__ import annotations
+
+from fontTools.ttLib import TTFont
+from fontTools.pens.svgPathPen import SVGPathPen
+
+# --- Warm darks ---
+# pi.dev: --color-warm-black
+WARM_BLACK = "#13110f"
+# pi.dev: --panel-base
+PANEL = "#212730"
+# pi.dev: --panel-soft-base
+PANEL_SOFT = "#252f3d"
+# pi.dev: --bg-deep, --bg-canvas
+BG_DEEP = "#0d1116"
+BG_CANVAS = "#161d27"
+
+# --- Creams ---
+# pi.dev: --color-parchment (the named "cream")
+PARCHMENT = "#dacbc2"
+# pi.dev: --color-moonstone (lighter cream / near-white)
+MOONSTONE = "#ebe7e4"
+# pi.dev: --color-driftwood (warm mid-gray, shadow tone)
+DRIFTWOOD = "#5c5752"
+
+# --- Warm accents (the fluid bronze / terracotta aesthetic) ---
+# pi.dev: --color-terracotta
+TERRACOTTA = "#844f3b"
+# pi.dev: --color-terracotta-light
+TERRACOTTA_LIGHT = "#b86b52"
+# pi.dev: --color-sunkissed
+SUNKISSED = "#e1b06e"
+
+# --- Secondary accents ---
+# pi.dev: --color-sage
+SAGE = "#a3a473"
+# pi.dev: --color-accent-blue / --accent
+ACCENT_BLUE = "#6a9fcc"
+# pi.dev: --color-tidal-blue / --thread-blue
+TIDAL_BLUE = "#4b607c"
+
+# --- Text ---
+# pi.dev: --text
+TEXT = "#ebe7e4"
+# pi.dev: --muted
+MUTED = "#9fa4ab"
+
+DEFAULT_FONT = "/System/Library/Fonts/Supplemental/Georgia Italic.ttf"
+
+
+def pi_path(font_path: str = DEFAULT_FONT) -> tuple[str, tuple[int, int, int, int], int]:
+ """Return (svg_path_d, bbox, unitsPerEm) for the π glyph (U+03C0)."""
+ font = TTFont(font_path)
+ cmap = font.getBestCmap()
+ gname = cmap[ord("π")]
+ pen = SVGPathPen(font.getGlyphSet())
+ font.getGlyphSet()[gname].draw(pen)
+ glyf = font["glyf"][gname]
+ bbox = (glyf.xMin, glyf.yMin, glyf.xMax, glyf.yMax)
+ return pen.getCommands(), bbox, font["head"].unitsPerEm
\ No newline at end of file
diff --git a/scripts/build-icon.py b/scripts/build-icon.py
new file mode 100644
index 0000000..6b02b89
--- /dev/null
+++ b/scripts/build-icon.py
@@ -0,0 +1,109 @@
+"""Build the pidex app icon and mark SVGs from Georgia Italic, using the
+Pi (pi.dev) design tokens so the workbench visually aligns with the Pi
+runtime.
+
+Outputs:
+ assets/icon.svg - flat 2D app icon (warm-black rounded square + cream faceted pi)
+ assets/mark.svg - flat pi mark on transparent, for in-UI use
+ assets/icon.png - rasterized icon at 1024x1024 (for Electron build/icon.png)
+ assets/mark.png - rasterized mark at 1024x1024
+"""
+
+from __future__ import annotations
+
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+REPO = Path(__file__).resolve().parent.parent
+ASSETS = REPO / "assets"
+SCRIPTS = Path(__file__).resolve().parent
+
+sys.path.insert(0, str(SCRIPTS))
+from _design import ( # noqa: E402
+ WARM_BLACK,
+ PARCHMENT,
+ MOONSTONE,
+ pi_path,
+)
+
+# Icon geometry (1024x1024 canvas, macOS-style squircle radius ~22.37%).
+ICON_SIZE = 1024
+ICON_RADIUS = 229
+
+# π placement: glyph centered, height ~56% of icon.
+SCALE = 0.56
+
+# Screen upper-left triangle (defined in glyph coords; the group transform flips Y).
+LIT_CLIP = "-22,980 1295,980 -22,-19"
+
+
+def build_icon_svg(d: str, bbox: tuple[int, int, int, int]) -> str:
+ gx = (bbox[0] + bbox[2]) / 2
+ gy = (bbox[1] + bbox[3]) / 2
+ cx = cy = ICON_SIZE / 2
+ return f"""
+"""
+
+
+def build_mark_svg(d: str, bbox: tuple[int, int, int, int]) -> str:
+ gx = (bbox[0] + bbox[2]) / 2
+ gy = (bbox[1] + bbox[3]) / 2
+ size = ICON_SIZE
+ cx = cy = size / 2
+ return f"""
+"""
+
+
+def render_png(svg: Path, png: Path, width: int) -> None:
+ if not shutil.which("inkscape"):
+ sys.exit("inkscape not found on PATH; install via brew install inkscape")
+ subprocess.run(
+ [
+ "inkscape",
+ str(svg),
+ "--export-type=png",
+ "--export-filename",
+ str(png),
+ "--export-width",
+ str(width),
+ ],
+ check=True,
+ )
+
+
+def main() -> None:
+ ASSETS.mkdir(exist_ok=True)
+ d, bbox, _ = pi_path()
+
+ icon_svg = ASSETS / "icon.svg"
+ mark_svg = ASSETS / "mark.svg"
+ icon_svg.write_text(build_icon_svg(d, bbox))
+ mark_svg.write_text(build_mark_svg(d, bbox))
+ print(f"wrote {icon_svg}")
+ print(f"wrote {mark_svg}")
+
+ render_png(icon_svg, ASSETS / "icon.png", ICON_SIZE)
+ render_png(mark_svg, ASSETS / "mark.png", ICON_SIZE)
+ print(f"wrote {ASSETS / 'icon.png'}")
+ print(f"wrote {ASSETS / 'mark.png'}")
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/scripts/build-screenshot.py b/scripts/build-screenshot.py
new file mode 100644
index 0000000..04de711
--- /dev/null
+++ b/scripts/build-screenshot.py
@@ -0,0 +1,180 @@
+"""Build a faithful pidex dashboard mockup SVG (and PNG) using the Pi
+(pi.dev) design tokens. Layout mirrors what the renderer ships: warm-black
+window with a panel-toned workspace sidebar on the left, session pane on
+the right, input pill at the bottom. Apple-style soft drop shadow under
+the window.
+
+Output:
+ docs/assets/screenshot.svg
+ docs/assets/screenshot.png (1440x900)
+"""
+
+from __future__ import annotations
+
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+REPO = Path(__file__).resolve().parent.parent
+OUT = REPO / "docs" / "assets"
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+from _design import ( # noqa: E402
+ WARM_BLACK,
+ PANEL,
+ PANEL_SOFT,
+ PARCHMENT,
+ MOONSTONE,
+ TERRACOTTA_LIGHT,
+ pi_path,
+)
+
+# Canvas
+W, H = 1440, 900
+
+# Window geometry (centered)
+WW, WH = 1200, 760
+WX = (W - WW) // 2
+WY = (H - WH) // 2
+WIN_R = 14
+
+# Sidebar
+SIDE_W = 300
+SIDE_BG = PANEL
+SIDE_PAD = 22
+
+# Warm neutral ground that complements the warm-black window
+BG = "#E2D8CC"
+
+
+def svg() -> str:
+ d, bbox, _ = pi_path()
+ gx = (bbox[0] + bbox[2]) / 2
+ gy = (bbox[1] + bbox[3]) / 2
+
+ # Sidebar π mark + pidex wordmark
+ mark_cx = WX + 36
+ mark_cy = WY + 44
+ mark_scale = 0.036 # ~37px tall
+ mark_transform = (
+ f"translate({mark_cx} {mark_cy}) "
+ f"scale({mark_scale} -{mark_scale}) "
+ f"translate({-gx} {-gy})"
+ )
+
+ # Workspace cards
+ cards = []
+ card_y = WY + 100
+ for i in range(4):
+ cy = card_y + i * 72
+ cards.append(
+ f''
+ f''
+ f''
+ f''
+ f''
+ )
+
+ pane_x = WX + SIDE_W
+ pane_w = WW - SIDE_W
+ header_y = WY + 22
+ cards_y = WY + 110
+ card_h = 132
+
+ header = (
+ f''
+ f''
+ f''
+ f''
+ f''
+ f''
+ )
+
+ main_cards = []
+ for i in range(2):
+ cy = cards_y + i * (card_h + 18)
+ main_cards.append(
+ f''
+ f''
+ f''
+ f''
+ f''
+ f''
+ f''
+ )
+
+ pill_y = WY + WH - 64
+ pill = (
+ f''
+ f''
+ f''
+ f''
+ )
+
+ return f"""
+"""
+
+
+def render_png(svg: Path, png: Path, width: int) -> None:
+ if not shutil.which("inkscape"):
+ sys.exit("inkscape not found on PATH; install via brew install inkscape")
+ subprocess.run(
+ ["inkscape", str(svg), "--export-type=png", "--export-filename", str(png), "--export-width", str(width)],
+ check=True,
+ )
+
+
+def main() -> None:
+ OUT.mkdir(parents=True, exist_ok=True)
+ svg_path = OUT / "screenshot.svg"
+ png_path = OUT / "screenshot.png"
+ svg_path.write_text(svg())
+ render_png(svg_path, png_path, W)
+ print(f"wrote {svg_path}")
+ print(f"wrote {png_path}")
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file