Skip to content

File Explorer

The File Explorer lets you browse the runner’s filesystem directly from the PizzaPi web UI — no terminal or SSH required. It appears as a docked side panel alongside the session viewer, showing the directory tree rooted at the agent’s current working directory.


Toggle the File Explorer with the keyboard shortcut ⌘⇧E (macOS) or Ctrl+Shift+E (Windows/Linux). You can also click the folder icon button in the session viewer header bar (desktop only; on mobile use the keyboard shortcut).

The button only appears when the active session has a connected runner with a known working directory (cwd). If no runner is connected, the button is hidden.


On desktop, the File Explorer opens as a docked panel inside the combined panel area. You can reposition it to the left, right, or bottom of the session viewer using the position picker in the panel header. Your position preference persists across sessions.

The panel also supports drag-to-reposition — click and hold the grip handle, then drag to a new edge.


The explorer displays the agent’s working directory as a collapsible tree. Each entry shows:

  • Folders — click to expand and lazy-load the directory contents from the runner. Folders show an amber folder icon that switches between closed and open states.
  • Files — click to open a read-only preview. Files display a type-specific emoji icon (e.g. 🟦 for .ts, 🐍 for .py, 🎨 for .css) and their size in human-readable format.
  • Symlinks — indicated with a suffix on the file name.

The breadcrumb bar at the top shows the current root path (cwd). Use the refresh button (↻) to re-fetch the directory listing if the filesystem has changed. Next to it, the Expand all and Collapse all buttons expand every folder up to three levels deep or collapse the whole tree.


Click any file to open it in the built-in viewer. Press Escape to return to the directory tree.

Text files open in a read-only monospaced preview with syntax-appropriate formatting. If the file exceeds 512 KB, it is truncated and a warning banner appears:

File truncated (showing first 512 KB of total size)

Markdown (.md and .mdx) files open in a dedicated Markdown viewer with a Preview / Raw toggle. Preview renders the file with LazyStreamdown formatting; Raw shows the plain source text. Like other text files, large Markdown files are read-only and truncated at 512 KB.

Image files (.png, .jpg, .jpeg, .gif, .webp, .svg, .bmp, .ico, .avif) open in a dedicated image viewer with:

  • Zoom controls — zoom in, zoom out, and reset buttons with a percentage indicator
  • Fit modes — toggle between “fit to view” (contain) and “actual size”
  • Transparency checkerboard — a checkerboard is always shown behind rendered images, which conveniently handles images with alpha channels
  • Dimensions — natural width × height shown in the header

Images are fetched as base64-encoded data with a 10 MB size limit.

Video files (.mp4, .m4v, .mov, .webm, .ogv, .ogg) open in the browser’s native video player with playback, volume, timeline, and fullscreen controls. Playback support depends on the browser and the video’s codec.

Videos have a 10 MB preview limit. Larger files show their size instead of transferring a partial, unplayable video.


The file search API powers the @-mention autocomplete in the message composer. When you type @ followed by a filename fragment, PizzaPi searches git-tracked files (plus untracked files that are not ignored) under the working directory and presents matching files as suggestions. If the workspace is not a git repository, the search returns an empty list with no error. This uses the same search-files endpoint described below.


The File Explorer is backed by three server endpoints. All require an authenticated session (cookie-based auth) and verify that the requesting user owns the runner.

POST /api/runners/:runnerId/files

Request body:

{
"path": "/home/user/project/src"
}

Response:

{
"ok": true,
"files": [
{
"name": "index.ts",
"path": "/home/user/project/src/index.ts",
"isDirectory": false,
"isSymlink": false,
"size": 2048
},
{
"name": "components",
"path": "/home/user/project/src/components",
"isDirectory": true
}
]
}

Each entry in files includes name, path, isDirectory, isSymlink, relativePath, and size in bytes (reported for both files and directories, though directory sizes are usually not meaningful).

POST /api/runners/:runnerId/read-file

Request body:

{
"path": "/home/user/project/src/index.ts",
"encoding": "utf8"
}
FieldTypeDefaultDescription
pathstring(required)Absolute path to the file
encoding"utf8" | "base64""utf8"Response encoding — use base64 for images and binary files
rejectTruncatedbooleanfalseWhen true, omit content if the file exceeds the encoding limit instead of returning partial content

Response:

{
"ok": true,
"content": "import React from 'react';\n...",
"truncated": false,
"size": 2048
}

Size limits depend on encoding:

EncodingMax sizeTimeout
utf8512 KB15 s
base6410 MB30 s

If the file exceeds the limit, content contains the first N bytes and truncated is true. When rejectTruncated is true, the response still reports size and truncated: true but omits content; video previews use this to avoid transferring unusable partial files.

POST /api/runners/:runnerId/search-files

Request body:

{
"cwd": "/home/user/project",
"query": "Button",
"limit": 50
}
FieldTypeDefaultDescription
cwdstring(required)Directory to search within
querystring(required)Filename search string (case-insensitive substring match)
limitnumber100Maximum number of results to return

Response:

{
"ok": true,
"files": [
{ "name": "Button.tsx", "path": "/home/user/project/src/components/Button.tsx" },
{ "name": "ButtonGroup.tsx", "path": "/home/user/project/src/components/ButtonGroup.tsx" }
]
}

If query is empty, the endpoint returns { "ok": true, "files": [] } immediately without hitting the runner.


All three endpoints enforce workspace root boundaries. The server checks the runner’s configured roots (the allowed workspace directories) and rejects any request where the path or cwd falls outside those roots.

If a request targets a path outside the allowed roots, the server responds with:

{
"error": "Runner cannot access path: /etc/passwd"
}

This returns HTTP 400. The check uses the cwdMatchesRoots() helper on the server side, ensuring that even crafted API requests cannot escape the workspace sandbox.


  • Large text files are truncated at 512 KB. The full file cannot be streamed through the explorer — use the agent’s read tool or a terminal for large files.
  • Binary files (executables, archives, databases) will either fail to render or display garbled content in the text viewer. Only images have dedicated rendering support.
  • No editing — the explorer is strictly read-only. There is no write-back capability.
  • No file search UI in the explorer panel — file search is currently available only through the @-mention autocomplete in the composer. A dedicated search bar in the explorer panel is planned.
  • Symlink targets are indicated with a marker but the target path is not displayed.
  • No syntax highlighting — text files render as plain monospaced text without language-aware coloring.