diff --git a/doc/sandbox-work-folders.md b/doc/sandbox-work-folders.md
index 88a9eec63a..7451052cd0 100644
--- a/doc/sandbox-work-folders.md
+++ b/doc/sandbox-work-folders.md
@@ -132,11 +132,16 @@ directories are not supported by this checkpoint format.
## API and UI
-The task, agent, project, and current-user pages expose a Files dialog using the
-shared file tree and viewer. It supports uploads, folder creation, previews,
-downloads, deletion, trash restore/purge, and sync state with the last agent save
-time. Direct file-operation timestamps are labeled separately as “Files updated”;
-a delete, restore, or idempotent receipt is not presented as an agent checkpoint.
+The task, agent, project, and current-user pages do not expose stored-file
+browsing. The 2026-09-08 design review removed these entry points: durable copies
+can lag behind a running sandbox and do not represent its complete filesystem.
+The persistence and synchronization APIs remain available to the runtime.
+
+Two separate features are deferred: debug inspection of persisted collections,
+and authorized inspection of the live sandbox filesystem across its task,
+agent, user, project, and repository context. The stored-file browser remains
+only as an unshipped Storybook prototype. It must not be presented as a live
+sandbox view. Page stories show the current pages without Files buttons.
All routes start at
`/api/companies/:companyId/work-folders/:scope/:ownerId`:
@@ -166,7 +171,9 @@ new pinned staging stack with the branch's Cloud image and matching migrator.
The deployed harness must target that tenant URL without launching a local
server. Enumerate every sandbox-capable adapter/engine and native profile
exposed by the stack; missing credentials or skipped required profiles block
-acceptance. Record real browser operations, two actual 180-second intervals,
+acceptance. Verify that the removed stored-file entry points are absent from
+the UI; browser-based file-management acceptance is deferred with the separate
+inspection features. Record API/runner operations, two actual 180-second intervals,
short-run flushes, independent task checkouts, identity/privacy boundaries,
interrupted saves, and recovery without the original sandbox or app volume.
diff --git a/ui/src/components/WorkFolderBrowser.tsx b/ui/src/components/WorkFolderBrowser.tsx
index 28761bac8e..8db51ad482 100644
--- a/ui/src/components/WorkFolderBrowser.tsx
+++ b/ui/src/components/WorkFolderBrowser.tsx
@@ -1,6 +1,6 @@
import { useId, useMemo, useRef, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
-import { Download, FolderOpen, FolderPlus, RefreshCw, RotateCcw, Trash2, Upload } from "lucide-react";
+import { Download, FolderPlus, RefreshCw, RotateCcw, Trash2, Upload } from "lucide-react";
import type { WorkFile, WorkFolderOwner } from "@paperclipai/shared";
import { workFoldersApi } from "@/api/work-folders";
import { FileTree, type FileTreeNode } from "@/components/FileTree";
@@ -9,7 +9,6 @@ import { Button } from "@/components/ui/button";
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
-import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
function tree(files: WorkFile[]) {
const root: FileTreeNode = { name: "", path: "", kind: "dir", children: [] };
@@ -30,16 +29,6 @@ function tree(files: WorkFile[]) {
sort(root.children); return root.children;
}
-export function WorkFolderButton({ owner, label = "Files" }: { owner: WorkFolderOwner; label?: string }) {
- return ;
-}
-
export function WorkFolderBrowser({ owner, exampleFiles }: { owner: WorkFolderOwner; exampleFiles?: WorkFile[] }) {
const queryClient = useQueryClient();
const [trash, setTrash] = useState(false);
diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx
index 7f90fcc257..626e6cd02a 100644
--- a/ui/src/pages/AgentDetail.tsx
+++ b/ui/src/pages/AgentDetail.tsx
@@ -59,7 +59,6 @@ import { cn } from "../lib/utils";
import { describeRunRetryState } from "../lib/runRetryState";
import { Button } from "@/components/ui/button";
import { Tabs } from "@/components/ui/tabs";
-import { WorkFolderButton } from "@/components/WorkFolderBrowser";
import { PageTabBar } from "../components/PageTabBar";
import { AuditFeed } from "./audit/AuditFeed";
import { Skeleton } from "@/components/ui/skeleton";
@@ -1374,8 +1373,6 @@ export function AgentDetail() {
) : null}
-
-
{actionError &&
{actionError}
}
{isPendingApproval && (
diff --git a/ui/src/pages/DesignGuide.tsx b/ui/src/pages/DesignGuide.tsx
index 4b89e233f5..5bdd23e832 100644
--- a/ui/src/pages/DesignGuide.tsx
+++ b/ui/src/pages/DesignGuide.tsx
@@ -1,5 +1,4 @@
import { useState } from "react";
-import { WorkFolderBrowser } from "@/components/WorkFolderBrowser";
import { ServicesList } from "./apps/app-detail/ServicesPanel";
import { ComposioProvenanceChip } from "./apps/ComposioProvenanceChip";
import type { ComposioServiceRow } from "./apps/composio-services";
@@ -483,14 +482,6 @@ export function DesignGuide() {
{/* ============================================================ */}
{/* COVERAGE */}
{/* ============================================================ */}
-
-
-
-
-
This page should be updated when new UI primitives or app-level patterns ship.
diff --git a/ui/src/pages/IssueDetail.tsx b/ui/src/pages/IssueDetail.tsx
index 5d31247f23..00dde7513c 100644
--- a/ui/src/pages/IssueDetail.tsx
+++ b/ui/src/pages/IssueDetail.tsx
@@ -171,7 +171,6 @@ import { useStreamlinedUiEnabled } from "../hooks/useStreamlinedUiEnabled";
import { workModeMetaFor } from "../lib/work-mode-meta";
import { IssueContinuationHandoff } from "../components/IssueContinuationHandoff";
import { IssueAttachmentsSection } from "../components/IssueAttachmentsSection";
-import { WorkFolderButton } from "@/components/WorkFolderBrowser";
import { IssueDocumentsSection } from "../components/IssueDocumentsSection";
import { IssuePlanDecompositionsSection } from "../components/IssuePlanDecompositionsSection";
import { IssueOutputSection } from "../components/issue-output/IssueOutputSection";
@@ -7470,8 +7469,6 @@ export function IssueDetail() {
/>
)}
-
-
{taskChatShellEnabled ? null : (
- {selectedCompanyId && }
);
diff --git a/ui/src/pages/ProjectDetail.tsx b/ui/src/pages/ProjectDetail.tsx
index 68405992a6..8d9a64df7e 100644
--- a/ui/src/pages/ProjectDetail.tsx
+++ b/ui/src/pages/ProjectDetail.tsx
@@ -37,7 +37,6 @@ import { Input } from "@/components/ui/input";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { Tabs } from "@/components/ui/tabs";
-import { WorkFolderButton } from "@/components/WorkFolderBrowser";
import { PluginLauncherOutlet } from "@/plugins/launchers";
import { PluginSlotMount, PluginSlotOutlet, usePluginSlots } from "@/plugins/slots";
import {
@@ -822,7 +821,6 @@ export function ProjectDetail() {
) : null}
- (
-
+ args: { scope: "task" },
+ argTypes: { scope: { control: false } },
+ render: ({ scope }: { scope: WorkFolderScope }) => (
+
),
-} satisfies Meta<{ scope: WorkFolderScope; scenario: WorkFolderScenario }>;
+} satisfies Meta<{ scope: WorkFolderScope }>;
export default meta;
type Story = StoryObj;
-const openFiles: NonNullable = async ({
- canvasElement,
- args,
-}) => {
- const label = workFolderLabels[args.scope];
- await userEvent.click(
- await within(canvasElement).findByRole(
- "button",
- { name: label },
- { timeout: 15000 },
- ),
- );
- await expect(
- await within(canvasElement.ownerDocument.body).findByRole("dialog", {
- name: label,
- }),
- ).toBeVisible();
-};
export const TaskPage: Story = { args: { scope: "task" } };
-export const TaskFilesOpen: Story = {
- args: { scope: "task" },
- play: openFiles,
-};
export const AgentPage: Story = { args: { scope: "agent" } };
-export const AgentFilesOpen: Story = {
- args: { scope: "agent" },
- play: openFiles,
-};
export const ProjectPage: Story = { args: { scope: "project" } };
-export const ProjectFilesOpen: Story = {
- args: { scope: "project" },
- play: openFiles,
-};
export const ProfileSettingsPage: Story = { args: { scope: "user" } };
-export const MyFilesOpen: Story = { args: { scope: "user" }, play: openFiles };
-export const TaskSaveFailed: Story = {
- args: { scope: "task", scenario: "failed" },
- play: openFiles,
-};
-export const ProjectEmptyFolder: Story = {
- args: { scope: "project", scenario: "empty" },
- play: openFiles,
-};
-export const MobileTaskFilesOpen: Story = {
+export const MobileTaskPage: Story = {
args: { scope: "task" },
globals: { viewport: { value: "mobile" } },
- play: openFiles,
};
diff --git a/ui/storybook/stories/work-folders.stories.tsx b/ui/storybook/stories/work-folders.stories.tsx
index bf6597445b..b7d6dc12d1 100644
--- a/ui/storybook/stories/work-folders.stories.tsx
+++ b/ui/storybook/stories/work-folders.stories.tsx
@@ -1,12 +1,8 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { expect, userEvent, within } from "storybook/test";
-import {
- WorkFolderBrowser,
- WorkFolderButton,
-} from "@/components/WorkFolderBrowser";
+import { WorkFolderBrowser } from "@/components/WorkFolderBrowser";
import { WorkFolderStoryProvider } from "../fixtures/WorkFolderStoryProvider";
import {
- workFolderLabels,
workFolderOwners,
type WorkFolderScenario,
} from "../fixtures/workFolders";
@@ -15,20 +11,19 @@ import type { WorkFolderScope } from "@paperclipai/shared";
type Args = {
scope: WorkFolderScope;
scenario: WorkFolderScenario;
- presentation: "browser" | "button";
};
const meta = {
- title: "Work folders/Components",
+ title: "Work folders/Stored-file prototype",
parameters: {
layout: "padded",
docs: {
description: {
component:
- "The actual reusable WorkFolderBrowser and WorkFolderButton. All file operations are in-memory fixtures: upload, create folder, delete, restore, purge, refresh, and download are safe to try. Change scope in Controls; use the toolbar for dark/light and mobile review. Reload a story to reset its files.",
+ "Unshipped stored-file browser prototype. Application entry points were removed because saved copies are not the live sandbox filesystem. This Storybook-only review surface uses disposable in-memory data; debug inspection and live sandbox browsing need separate designs.",
},
},
},
- args: { scope: "task", scenario: "saved", presentation: "browser" },
+ args: { scope: "task", scenario: "saved" },
argTypes: {
scope: { control: "select", options: ["task", "agent", "project", "user"] },
scenario: {
@@ -43,22 +38,15 @@ const meta = {
"uploadFailed",
],
},
- presentation: { control: "radio", options: ["browser", "button"] },
},
- render: ({ scope, scenario, presentation }) => (
-
+ render: ({ scope, scenario }) => (
+