[[
wikihub
]]
Search
⌘K
Explore
People
For Agents
Sign in
Explore
People
For Agents
Sign in
@jacobcole / picortex — planning / docs/specs/004-file-browser.md
Suggest edit
Cancel
Submit suggestion
Title
Name
Note
--- visibility: public --- # Spec 004 — File browser **Status:** Draft **Related:** [PRD FR-19](../prd/001-picortex-v1.md#mobile-first-web-ui), [bettergpt mockups](../mockups/README.md) ## Goal For any chat, show the chat's home directory as a tree. Tapping a file shows its contents (syntax-highlighted for code, rendered for markdown, image-preview for images). Inspiration: Cortex's `mockups/bettergpt/index-split-view-filebrowser.html`. ## Routes - `GET /api/chats/:chat_id/files/tree?path=<subpath>` — JSON: `[{name, path, type:"dir"|"file", size, mtime}]` - `GET /api/chats/:chat_id/files/content?path=<subpath>` — raw bytes; client picks renderer from MIME/extension - `POST /api/chats/:chat_id/files?path=<subpath>` — write (later) - `DELETE /api/chats/:chat_id/files?path=<subpath>` — delete (later) Backend runs each as `sudo -u chat-<hex>` → reads the chat user's home. Paths are always relative to home; `..` is rejected via realpath-and-prefix check. ## UI ### Desktop / tablet Three columns: `[Messages | File tree | File viewer or Terminal]`. Tree + viewer share ~50/50 of the right two-thirds; messages fixed 1/3. ### Mobile Swipe-tab layout. Tab 2 is the file browser; it splits vertically into tree (top 40%) + viewer (bottom 60%) once a file is selected. Back-gesture returns to messages. Mockup references in [docs/mockups/README.md](../mockups/README.md). ## Renderers | Type | Renderer | |---|---| | Markdown | `react-markdown` with `remark-gfm` | | Code | `react-syntax-highlighter` with Prism themes | | JSON/YAML | syntax-highlighted, collapsible tree | | Image | `<img>` with width 100% | | PDF | `<iframe>` or `react-pdf` (post-v1) | | Binary | "N bytes, not previewed" + download link | ## Hidden files Show dotfiles by default (Jacob wants to see `.picortex/prompts/discriminator.md`). Exclude `.git/objects/*` (noise) behind a "show all" toggle. ## Security - Path check: `realpath(home + path)` must start with `realpath(home)`. - Enforce read-size cap (10 MB). Above that, return `413`. - Content-type sniff server-side; never echo untrusted `Content-Type` headers from the filesystem. - HTML content is returned as `text/plain` unless explicitly requested as rendered markdown. ## Caching - Tree responses cached with `ETag` (home-dir mtime + size-of-listing hash) - File content cached with `ETag` (file mtime + size) - Browser cache: `Cache-Control: private, max-age=5` ## Testing - **Unit:** path-sanitizer rejects `..`, symlinks-out, absolute paths, null bytes. - **Integration:** real filesystem; navigate, assert sorted, assert rejected on another chat's home. - **E2E:** Playwright on mobile; tap through tree, render markdown. ## Open questions - OQ1: Do we want write support in v1? (Yes, for editing `.picortex/prompts/discriminator.md` directly.) Post-S7. - OQ2: Search within a chat's files? (Defer to v0.2 — the terminal can `rg`.)