File Explorer
Bundled file explorer module for browsing, editing, and uploading filesystem content.
What it does
file-explorer is a bundled module for navigating filesystem paths in the running Clapilot environment (workspace/container-mounted paths). It combines a Finder-style file table with an inline editor/preview pane: browse and search folders, open and edit text files, preview browser-renderable documents, create folders, and upload individual files or whole folders.
Since March 6, 2026, file-explorer is rendered directly inside the React app shell instead of an iframe (it was the first bundled module to move). The module backend contract stayed unchanged; only the UI host moved into the standard Clapilot view hierarchy.
How to open it
- Web:
/modules/file-explorer(bundled module, slugfile-explorer; manifestbundled-modules/file-explorer/module.json,entry: index.html,renderer: react, iconfolder). - Backend:
bundled-modules/file-explorer/api/handler.mjs. - React host UI:
src/components/modules/file-explorer-module.tsx; route integration:src/app/(app)/modules/[slug]/page.tsx. - Legacy bundled frontend assets remain in
bundled-modules/file-explorer/ui/index.ts(compiled toui/index.js) but are not the active runtime whilerendererisreact.
Key workflows
Browse and search
- Pick a root or type a path in the path selector; absolute and relative navigation are supported, with back/forward history buttons.
- When the open directory has a parent, the table shows a
..row pinned above the entries (hidden while searching); clicking it navigates to the parent folder, same as theUpbutton in the list header. - Sort the Finder-style table by name, modified time, size, or type (ascending/descending).
- Use the search input to search the currently opened folder and all subfolders by name (
GET /search). Results show the relative subfolder location under each entry name; a truncation hint appears when the capped recursive walk stops early. - The last opened directory is restored after a browser reload: the current path is mirrored into the
?path=URL query parameter and intolocalStorage, so reloading (or sharing the URL) reopens the same folder. If the remembered path no longer exists, the module falls back to the default root.
Open, preview, and edit files
Opena text file to edit it in the inline editor canvas on the right side of the file list, then save it back (POST /save-file).- Images, PDFs, audio, and video render inline in the right-side preview pane instead of falling back to the text editor; browser-renderable files are not blocked by a fixed inline preview size limit.
Downloadfetches the raw file.
Manage and upload
- Row actions:
Open,Download,Copy Path,Rename,Delete,New Folder Here,Upload Files/Folder Here. They are available both from the row...dropdown and from a right-click context menu on any row. - Right-clicking the empty list area opens a folder context menu with
New Folder,Upload Files,Upload Folder, andRefreshfor the current directory. - Create-folder, rename, and delete flows use app-styled dialogs (no browser-native
prompt/confirm). - Folder upload uses browser directory selection (
webkitdirectory) and preserves nested relative paths. - Drag & drop supports both individual files and folders and uploads into the currently open directory. Single-file uploads go through the same
upload-folderendpoint as folder uploads.
How the agent can drive it
The File Explorer is UI-only: there are no file_explorer_* agent tools. Agents that need filesystem access use their native runtime shell/file tool contracts instead. Other clients may reuse the module API directly — for example, the Apple client downloads chat media through the authenticated GET /api/modules/file-explorer/api/download route.
Module API reference
Base: /api/modules/file-explorer/api
| Route | Purpose |
|---|---|
GET /roots | list available root paths |
GET /list?path=<path> | list a directory |
GET /search?path=<path>&q=<query> | recursive name search under a directory; returns { results, truncated }, capped at 200 results / depth 12 / 25k scanned entries / 8s, skipping node_modules, .git, .next, and /proc, /sys, /dev, /run |
GET /file?path=<path> | read file content |
GET /download?path=<path> | download raw file |
POST /mkdir ({ path }) | create a folder |
POST /rename ({ path, newName }) | rename a file/folder |
POST /delete ({ path }) | delete a file/folder |
POST /upload-folder (multipart/form-data with targetPath + repeated files) | upload files or whole folders |
POST /save-file ({ path, content }) | save inline-edited text content |
Configuration & limits
- Paths are restricted to the roots exposed by
GET /roots, and the backend enforces that restriction on every read and write: any resolved path outside the allowed roots is rejected with403.GET /rootsis derived from the same allowlist the API enforces, so it never advertises a root that would be rejected or that does not exist on disk. - Containment is enforced on the resolved real path, not on the requested string: existing targets are resolved with
realpath, and creation targets are resolved through the nearest existing parent directory plus the remaining lexical suffix. A symlink inside an allowed root that points outside it (and a dangling symlink) is rejected with403for every read, write, rename, delete, upload, and download. Authorization runs immediately before each filesystem operation; a residual TOCTOU window remains for callers that can already create symlinks inside an allowed root. - Default roots for normal workspace users are the workspace directory and any paths configured via
FILE_EXPLORER_ROOTS. The workspace directory is resolved with the same precedence assrc/lib/runtime-env.ts(CLAPILOT_WORKSPACE_DIR, thenOPENCLAW_WORKSPACE_DIR, default/app/workspace), so the module agrees with the app in Docker and innpm run dev:local-native. - The module directory is a read-only root for non-privileged users. It holds product code that the module API route imports and executes (
api/handler.mjs), sosave-file,mkdir,rename,delete, andupload-folderare rejected with403there. - The runtime state directory (
CLAPILOTAICORE_HOME/CLAPILOTAICORE_STATE_DIR, default/app/workspace/.clapilotaicore) is denied for non-privileged users and hidden from listings and search, because it holdsclapilotaicore.json,system-auth.json,CODEX_HOME, and the CLI homes (provider API keys and auth tokens). renameanddeletereject a target that is an allowed root itself, so a single request can no longer move or recursively wipe a whole root.- The
Container Root(/) entry is a privileged root: it is only offered — and only accepted by the API — for admins on an instance with Developer mode enabled, or for trusted service/agent callers. This holds even when/is configured viaFILE_EXPLORER_ROOTS. Non-privileged users previously reached the whole container filesystem through this root; the gate is declared insrc/lib/module-store/developer-mode-modules.tsand injected per request bysrc/app/api/modules/[slug]/api/[...endpointPath]/route.ts. - The module uses the same app-shell layout behavior as native Clapilot pages, so chat/sidebar sizing is handled by the main React hierarchy instead of iframe host offsets.
Troubleshooting
- A file opens as garbled text: non-text formats render in the preview pane only when the browser can display them; other binary formats should be downloaded instead of opened.
- Uploads land in the wrong place: drag & drop always uploads into the currently open directory; navigate there first or use
Upload Folder Hereon the target row.
File context menu
Right-click a file for Rename, Copy, Share, Download and Delete. Copy creates an independent sibling file without overwriting existing files. Share opens Email or Chat (Channel/Direct message); printable PDF/images also support Fax and Post. Sharing prepares a revocable document link or a review screen and never sends immediately. All filesystem operations retain File Manager path restrictions.
Internal chat sharing links to /modules/file-explorer?path=<parent>&file=<absolute-path>
with URL-encoded values. Opening the link loads the parent directory and selects
and opens the exact file, retaining File Manager authorization. A missing or
unauthorized linked file does not fall back to a different directory. The Apple
clients open these authenticated file links in-app.
Internal links in chat automatically show authenticated inline media or a clickable reference to the original item. Videos have playback controls, images have previews, and other documents/module items use document-style references. This also applies to existing messages and the Apple clients; no exported copy or public link is generated.
