feat(settings): alphabetize experimental cards and drop the Experimental chip (#10924)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The Instance Settings area exposes an Experimental page that lists opt-in feature toggles as cards. > - New experimental features were appended to the list over time, so the cards sat in insertion order with no predictable arrangement. > - An unordered list is hard to scan when you are looking for one specific feature. > - Each card also carried a small "Experimental" secondary badge, which is redundant on a page that is itself titled Experimental. > - This pull request sorts every card alphabetically by its title and removes that redundant badge. > - The benefit is a list that is faster to scan and headings that are less cluttered. ## Linked Issues or Issue Description No public GitHub issue exists for this change, so the enhancement is described inline following `.github/ISSUE_TEMPLATE/enhancement.yml`: **What existing behavior does this improve?** The Instance Settings → Experimental page, which lists opt-in feature toggles as a stack of cards. **Subsystem affected** UI — the Instance Experimental settings page (`ui/src/pages/InstanceExperimentalSettings.tsx`). **Current behavior** Cards render in insertion order (the order features happened to be added), so finding a specific feature means scanning the whole list. Several headings also carry a redundant "Experimental" secondary badge. **Proposed behavior** Cards render top-to-bottom in A→Z order by title, and no card shows an "Experimental" secondary badge. Toggle logic, footnotes, conditional visibility, and the "Managed by Paperclip Cloud" badge are unchanged. **Reason and benefit** Alphabetical order makes the list predictable and quick to scan for a specific feature. The "Experimental" badge repeats information already conveyed by the page title, so removing it declutters the headings. **Breaking changes** None. This touches card render order and the removal of a decorative badge only — no state, persistence, toggle, or visibility logic changes. ## What Changed - Sorted every card on the Instance Experimental settings page alphabetically by its heading title. - Removed the redundant "Experimental" secondary badge from the card headings (previously on Apps, Cases, and Chat-Style Tasks). - Added tests asserting the cards render in case-insensitive alphabetical order and that no card renders an "Experimental" secondary badge. - No behavior change: toggle handlers, footnotes, managed-key handling, and conditional cards (Conference Room Chat, worktree-scoped run) are untouched and now sort into their alphabetical slots. ## Verification - `pnpm check:token-gates` → all 3 gates CLEAN. - `npx vitest run ui/src/pages/InstanceExperimentalSettings.test.tsx` → 32/32 tests pass (the suite renders the real component and now covers ordering + badge removal). - `pnpm --filter @paperclipai/ui typecheck` (`tsc -b`) → clean. - Manual: open Instance Settings → Experimental. The cards read A→Z and no card shows an "Experimental" chip. ## Risks Low risk. The change is limited to one page component: card render order and the removal of a decorative badge, plus new tests. No state, persistence, toggle, or visibility logic is modified. ## Model Used Claude Opus 4.8 (Anthropic), model id `claude-opus-4-8`, extended thinking enabled, tool use enabled. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
00a24d7e8f
commit
b1b7a9dff6
|
|
@ -862,3 +862,67 @@ describe("InstanceExperimentalSettings — cloud-managed keys", () => {
|
|||
expect(mockInstanceSettingsApi.updateExperimental).toHaveBeenCalledWith({ enableApps: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe("InstanceExperimentalSettings — card ordering and headings (PAP-393)", () => {
|
||||
let container: HTMLDivElement;
|
||||
let root: Root | null = null;
|
||||
|
||||
async function renderPage(settings: InstanceExperimentalSettingsWithManaged) {
|
||||
mockInstanceSettingsApi.getExperimental.mockResolvedValue({ ...settings });
|
||||
root = createRoot(container);
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: { queries: { retry: false } },
|
||||
});
|
||||
flushSync(() => {
|
||||
root!.render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<InstanceExperimentalSettings />
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
});
|
||||
await flushReact();
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
mockInstanceSettingsApi.updateExperimental.mockImplementation(async (patch) => ({
|
||||
...defaultExperimentalSettings(),
|
||||
...patch,
|
||||
}));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
flushSync(() => {
|
||||
root?.unmount();
|
||||
});
|
||||
root = null;
|
||||
container.remove();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders every card heading in alphabetical order", async () => {
|
||||
await renderPage(defaultExperimentalSettings());
|
||||
|
||||
const headings = [...container.querySelectorAll("h2")].map(
|
||||
(heading) => heading.textContent ?? "",
|
||||
);
|
||||
|
||||
// Sanity: the page rendered a meaningful set of cards, not an empty list.
|
||||
expect(headings.length).toBeGreaterThan(10);
|
||||
|
||||
const alphabetical = [...headings].sort((a, b) =>
|
||||
a.localeCompare(b, undefined, { sensitivity: "base" }),
|
||||
);
|
||||
expect(headings).toEqual(alphabetical);
|
||||
});
|
||||
|
||||
it("no longer renders an 'Experimental' secondary badge on any card", async () => {
|
||||
await renderPage(defaultExperimentalSettings());
|
||||
|
||||
const badges = [...container.querySelectorAll('[data-slot="badge"]')].map(
|
||||
(badge) => badge.textContent?.trim(),
|
||||
);
|
||||
expect(badges).not.toContain("Experimental");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ function ManagedByCloudBadge() {
|
|||
|
||||
function ExperimentalToggleCard({
|
||||
title,
|
||||
experimental = false,
|
||||
description,
|
||||
footnote,
|
||||
checked,
|
||||
|
|
@ -97,7 +96,6 @@ function ExperimentalToggleCard({
|
|||
ariaLabel,
|
||||
}: {
|
||||
title: string;
|
||||
experimental?: boolean;
|
||||
description: string;
|
||||
footnote?: string;
|
||||
checked: boolean;
|
||||
|
|
@ -113,7 +111,6 @@ function ExperimentalToggleCard({
|
|||
<div className="space-y-1.5">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<h2 className="text-sm font-semibold">{title}</h2>
|
||||
{experimental ? <Badge variant="secondary">Experimental</Badge> : null}
|
||||
{isManaged ? <ManagedByCloudBadge /> : null}
|
||||
</div>
|
||||
<p className="max-w-2xl text-sm text-muted-foreground">{description}</p>
|
||||
|
|
@ -460,66 +457,8 @@ export function InstanceExperimentalSettings() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{inWorktree ? (
|
||||
<Card className="block p-5">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<h2 className="text-sm font-semibold">Run tasks in this worktree</h2>
|
||||
{worktreeRunExecutionManaged ? <ManagedByCloudBadge /> : null}
|
||||
</div>
|
||||
<p className="max-w-2xl text-sm text-muted-foreground">
|
||||
This is an isolated git-worktree preview instance. Turn this on to let the scheduler execute runs
|
||||
here. Only tasks created after enabling will run automatically — copied/pre-existing tasks stay
|
||||
parked. Toggling off and on resets the cutoff.
|
||||
</p>
|
||||
</div>
|
||||
<ToggleSwitch
|
||||
checked={enableWorktreeRunExecution}
|
||||
onCheckedChange={(checked) => {
|
||||
if (worktreeRunExecutionManaged) return;
|
||||
toggleMutation.mutate({ enableWorktreeRunExecution: checked });
|
||||
}}
|
||||
disabled={toggleMutation.isPending || worktreeRunExecutionManaged}
|
||||
aria-label="Toggle worktree run execution setting"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{worktreeRunExecutionState.kind === "armed" ? (
|
||||
<div className="flex items-center gap-2 rounded-md border border-emerald-500/30 bg-emerald-500/5 px-3 py-2 text-sm text-foreground">
|
||||
<Play className="h-4 w-4 shrink-0 text-emerald-600" />
|
||||
<span>
|
||||
Running tasks created after{" "}
|
||||
<span className="font-medium">
|
||||
{formatActivationTimestamp(worktreeRunExecutionState.activatedAt)}
|
||||
</span>
|
||||
.
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{worktreeRunExecutionState.kind === "fail_closed" ? (
|
||||
<div className="flex items-start gap-2 rounded-md border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-sm">
|
||||
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-amber-700" />
|
||||
<div className="space-y-0.5">
|
||||
<p className="font-medium text-foreground">Execution is suppressed — effectively off.</p>
|
||||
<p className="text-muted-foreground">
|
||||
{worktreeRunExecutionState.reason === "instance_mismatch"
|
||||
? "This setting was armed in a different instance and copied here, so no tasks run automatically."
|
||||
: "This setting is missing its activation cutoff, so no tasks run automatically."}{" "}
|
||||
Toggle it off and back on to arm execution for tasks created here.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</Card>
|
||||
) : null}
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Apps"
|
||||
experimental
|
||||
description="Show the Apps navigation and allow access to app connections, gateways, and advanced app tooling."
|
||||
checked={enableApps}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableApps: checked })}
|
||||
|
|
@ -528,206 +467,6 @@ export function InstanceExperimentalSettings() {
|
|||
ariaLabel="Toggle apps experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Cases"
|
||||
experimental
|
||||
description="Durable work products (blog posts, tweet storms…) that tasks create and iterate on. Adds the Cases tab and the agent case API."
|
||||
footnote="Turning Cases off hides the tab and blocks the case API; existing case data is kept."
|
||||
checked={enableCases}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableCases: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableCases}
|
||||
ariaLabel="Toggle cases experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Enable Environments"
|
||||
description="Show environment management in company settings and allow project and agent environment assignment controls."
|
||||
checked={enableEnvironments}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableEnvironments: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableEnvironments}
|
||||
ariaLabel="Toggle environments experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Built-in Agents"
|
||||
description="Show Paperclip-managed built-in agent surfaces, including built-in roster badges, the Built-in agents tab, and built-in agent setup controls."
|
||||
checked={enableBuiltInAgents}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableBuiltInAgents: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableBuiltInAgents}
|
||||
ariaLabel="Toggle built-in agents experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Beta skills"
|
||||
description="Allow agents to pin beta releases of the Paperclip core skill. Disabling this returns every agent to the default live skill without removing saved pins."
|
||||
checked={enableBetaSkills}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableBetaSkills: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableBetaSkills}
|
||||
ariaLabel="Toggle beta skills experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Summaries"
|
||||
description="Show Summarizer-generated status slots on project and workspace pages, with on-demand refresh and revision history. Existing summary data is kept when this is disabled."
|
||||
footnote="Status Cards requires Summaries. Disabling Summaries also disables Status Cards."
|
||||
checked={enableSummaries}
|
||||
onCheckedChange={(checked) =>
|
||||
toggleMutation.mutate(
|
||||
checked || !enableStatusCards
|
||||
? { enableSummaries: checked }
|
||||
: { enableSummaries: false, enableStatusCards: false },
|
||||
)
|
||||
}
|
||||
disabled={toggleMutation.isPending || summariesRequiredByManagedStatusCards}
|
||||
managed={managedKeys.enableSummaries}
|
||||
ariaLabel="Toggle summaries experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Experimental File Viewer"
|
||||
description="Show task detail controls for browsing and previewing workspace files relative to a task."
|
||||
checked={enableExperimentalFileViewer}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableExperimentalFileViewer: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableExperimentalFileViewer}
|
||||
ariaLabel="Toggle experimental file viewer setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Status Cards"
|
||||
description="Enable the experimental shared status-card board and its gated API. Existing card data is kept when this is disabled."
|
||||
footnote="Enabling Status Cards also enables Summaries."
|
||||
checked={enableStatusCards}
|
||||
onCheckedChange={(checked) =>
|
||||
toggleMutation.mutate(
|
||||
checked
|
||||
? { enableSummaries: true, enableStatusCards: true }
|
||||
: { enableStatusCards: false },
|
||||
)
|
||||
}
|
||||
disabled={toggleMutation.isPending || statusCardsBlockedByManagedSummaries}
|
||||
managed={managedKeys.enableStatusCards}
|
||||
ariaLabel="Toggle status cards experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Enable External Objects"
|
||||
description="Detect external URLs in issues and show resolved status for pull requests, tickets, and other referenced work objects."
|
||||
checked={enableExternalObjects}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableExternalObjects: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableExternalObjects}
|
||||
ariaLabel="Toggle external objects experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Decisions"
|
||||
description="Show the Decisions item in the main sidebar — the attention home that surfaces the tasks awaiting your input — while the surface is still being evaluated."
|
||||
checked={enableDecisions}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableDecisions: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableDecisions}
|
||||
ariaLabel="Toggle decisions experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Goals Sidebar Link"
|
||||
description="Restore the Goals item in the main sidebar while the goals surface is being evaluated."
|
||||
checked={enableGoalsSidebarLink}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableGoalsSidebarLink: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableGoalsSidebarLink}
|
||||
ariaLabel="Toggle goals sidebar link experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Enable Isolated Workspaces"
|
||||
description="Show execution workspace controls in project configuration and allow isolated workspace behavior for new and existing task runs."
|
||||
checked={enableIsolatedWorkspaces}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableIsolatedWorkspaces: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableIsolatedWorkspaces}
|
||||
ariaLabel="Toggle isolated workspaces experimental setting"
|
||||
/>
|
||||
|
||||
{SHOW_CONFERENCE_ROOM_EXPERIMENTAL_SETTING ? (
|
||||
<ExperimentalToggleCard
|
||||
title="Conference Room Chat"
|
||||
description="Adds a Conference Room — one chat where you and your whole team work together — plus the live activity feed and the redesigned onboarding. Also restyles task threads as chat bubbles. Turn off anytime to restore the classic UI."
|
||||
checked={enableConferenceRoomChat}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableConferenceRoomChat: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableConferenceRoomChat}
|
||||
ariaLabel="Toggle conference room chat experimental setting"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Task Plan Decomposition Panel"
|
||||
description="Show accepted-plan decomposition history on task detail pages. Intended for debugging and validating subtask creation behavior while the presentation is still being refined."
|
||||
checked={enableIssuePlanDecompositions}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableIssuePlanDecompositions: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableIssuePlanDecompositions}
|
||||
ariaLabel="Toggle task plan decomposition panel experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Chat-Style Tasks"
|
||||
experimental
|
||||
description="Reimagines the task detail page as a live conversation with your agents: chat bubbles for people and agents, streaming activity — thinking, tool calls, diffs — that folds into a one-line summary when a turn finishes, inline plan/question/permission cards, a three-mode composer (Agent · Plan · Ask), and a resizable Properties · Plan · Artifacts pane."
|
||||
footnote="Turning this off instantly restores the classic task page. No task data is affected."
|
||||
checked={enableTaskChatRedesign}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableTaskChatRedesign: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableTaskChatRedesign}
|
||||
ariaLabel="Toggle chat-style tasks experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Task Watchdogs"
|
||||
description="Show task detail controls for configuring watchdog agents that verify stopped task subtrees and restore live paths when work should continue."
|
||||
checked={enableTaskWatchdogs}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableTaskWatchdogs: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableTaskWatchdogs}
|
||||
ariaLabel="Toggle task watchdogs experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Server Info Debug View"
|
||||
description='Show a "Server" section in the account drawer with the current server restart time and running commit.'
|
||||
checked={enableServerInfoDebugView}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableServerInfoDebugView: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableServerInfoDebugView}
|
||||
ariaLabel="Toggle server info debug view experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Smoke Lab"
|
||||
description='Add a "Smoke Lab" tab under Apps → Developer and an "Integration smoke" card on the dashboard for exercising every integration path against deterministic local fixtures (fake OAuth provider + loopback MCP servers). Private (non-public) deployments only.'
|
||||
checked={enableSmokeLab}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableSmokeLab: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableSmokeLab}
|
||||
ariaLabel="Toggle smoke lab experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Auto-Restart Dev Server When Idle"
|
||||
description="In `pnpm dev:once`, wait for all queued and running local agent runs to finish, then restart the server automatically when backend changes or migrations make the current boot stale."
|
||||
checked={autoRestartDevServerWhenIdle}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ autoRestartDevServerWhenIdle: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.autoRestartDevServerWhenIdle}
|
||||
ariaLabel="Toggle guarded dev-server auto-restart"
|
||||
/>
|
||||
|
||||
<Card className="block p-5">
|
||||
<div className="flex flex-col gap-5">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
|
|
@ -818,6 +557,261 @@ export function InstanceExperimentalSettings() {
|
|||
</div>
|
||||
</Card>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Auto-Restart Dev Server When Idle"
|
||||
description="In `pnpm dev:once`, wait for all queued and running local agent runs to finish, then restart the server automatically when backend changes or migrations make the current boot stale."
|
||||
checked={autoRestartDevServerWhenIdle}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ autoRestartDevServerWhenIdle: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.autoRestartDevServerWhenIdle}
|
||||
ariaLabel="Toggle guarded dev-server auto-restart"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Beta skills"
|
||||
description="Allow agents to pin beta releases of the Paperclip core skill. Disabling this returns every agent to the default live skill without removing saved pins."
|
||||
checked={enableBetaSkills}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableBetaSkills: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableBetaSkills}
|
||||
ariaLabel="Toggle beta skills experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Built-in Agents"
|
||||
description="Show Paperclip-managed built-in agent surfaces, including built-in roster badges, the Built-in agents tab, and built-in agent setup controls."
|
||||
checked={enableBuiltInAgents}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableBuiltInAgents: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableBuiltInAgents}
|
||||
ariaLabel="Toggle built-in agents experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Cases"
|
||||
description="Durable work products (blog posts, tweet storms…) that tasks create and iterate on. Adds the Cases tab and the agent case API."
|
||||
footnote="Turning Cases off hides the tab and blocks the case API; existing case data is kept."
|
||||
checked={enableCases}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableCases: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableCases}
|
||||
ariaLabel="Toggle cases experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Chat-Style Tasks"
|
||||
description="Reimagines the task detail page as a live conversation with your agents: chat bubbles for people and agents, streaming activity — thinking, tool calls, diffs — that folds into a one-line summary when a turn finishes, inline plan/question/permission cards, a three-mode composer (Agent · Plan · Ask), and a resizable Properties · Plan · Artifacts pane."
|
||||
footnote="Turning this off instantly restores the classic task page. No task data is affected."
|
||||
checked={enableTaskChatRedesign}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableTaskChatRedesign: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableTaskChatRedesign}
|
||||
ariaLabel="Toggle chat-style tasks experimental setting"
|
||||
/>
|
||||
|
||||
{SHOW_CONFERENCE_ROOM_EXPERIMENTAL_SETTING ? (
|
||||
<ExperimentalToggleCard
|
||||
title="Conference Room Chat"
|
||||
description="Adds a Conference Room — one chat where you and your whole team work together — plus the live activity feed and the redesigned onboarding. Also restyles task threads as chat bubbles. Turn off anytime to restore the classic UI."
|
||||
checked={enableConferenceRoomChat}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableConferenceRoomChat: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableConferenceRoomChat}
|
||||
ariaLabel="Toggle conference room chat experimental setting"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Decisions"
|
||||
description="Show the Decisions item in the main sidebar — the attention home that surfaces the tasks awaiting your input — while the surface is still being evaluated."
|
||||
checked={enableDecisions}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableDecisions: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableDecisions}
|
||||
ariaLabel="Toggle decisions experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Enable Environments"
|
||||
description="Show environment management in company settings and allow project and agent environment assignment controls."
|
||||
checked={enableEnvironments}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableEnvironments: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableEnvironments}
|
||||
ariaLabel="Toggle environments experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Enable External Objects"
|
||||
description="Detect external URLs in issues and show resolved status for pull requests, tickets, and other referenced work objects."
|
||||
checked={enableExternalObjects}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableExternalObjects: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableExternalObjects}
|
||||
ariaLabel="Toggle external objects experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Enable Isolated Workspaces"
|
||||
description="Show execution workspace controls in project configuration and allow isolated workspace behavior for new and existing task runs."
|
||||
checked={enableIsolatedWorkspaces}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableIsolatedWorkspaces: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableIsolatedWorkspaces}
|
||||
ariaLabel="Toggle isolated workspaces experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Experimental File Viewer"
|
||||
description="Show task detail controls for browsing and previewing workspace files relative to a task."
|
||||
checked={enableExperimentalFileViewer}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableExperimentalFileViewer: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableExperimentalFileViewer}
|
||||
ariaLabel="Toggle experimental file viewer setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Goals Sidebar Link"
|
||||
description="Restore the Goals item in the main sidebar while the goals surface is being evaluated."
|
||||
checked={enableGoalsSidebarLink}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableGoalsSidebarLink: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableGoalsSidebarLink}
|
||||
ariaLabel="Toggle goals sidebar link experimental setting"
|
||||
/>
|
||||
|
||||
{inWorktree ? (
|
||||
<Card className="block p-5">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<h2 className="text-sm font-semibold">Run tasks in this worktree</h2>
|
||||
{worktreeRunExecutionManaged ? <ManagedByCloudBadge /> : null}
|
||||
</div>
|
||||
<p className="max-w-2xl text-sm text-muted-foreground">
|
||||
This is an isolated git-worktree preview instance. Turn this on to let the scheduler execute runs
|
||||
here. Only tasks created after enabling will run automatically — copied/pre-existing tasks stay
|
||||
parked. Toggling off and on resets the cutoff.
|
||||
</p>
|
||||
</div>
|
||||
<ToggleSwitch
|
||||
checked={enableWorktreeRunExecution}
|
||||
onCheckedChange={(checked) => {
|
||||
if (worktreeRunExecutionManaged) return;
|
||||
toggleMutation.mutate({ enableWorktreeRunExecution: checked });
|
||||
}}
|
||||
disabled={toggleMutation.isPending || worktreeRunExecutionManaged}
|
||||
aria-label="Toggle worktree run execution setting"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{worktreeRunExecutionState.kind === "armed" ? (
|
||||
<div className="flex items-center gap-2 rounded-md border border-emerald-500/30 bg-emerald-500/5 px-3 py-2 text-sm text-foreground">
|
||||
<Play className="h-4 w-4 shrink-0 text-emerald-600" />
|
||||
<span>
|
||||
Running tasks created after{" "}
|
||||
<span className="font-medium">
|
||||
{formatActivationTimestamp(worktreeRunExecutionState.activatedAt)}
|
||||
</span>
|
||||
.
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{worktreeRunExecutionState.kind === "fail_closed" ? (
|
||||
<div className="flex items-start gap-2 rounded-md border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-sm">
|
||||
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-amber-700" />
|
||||
<div className="space-y-0.5">
|
||||
<p className="font-medium text-foreground">Execution is suppressed — effectively off.</p>
|
||||
<p className="text-muted-foreground">
|
||||
{worktreeRunExecutionState.reason === "instance_mismatch"
|
||||
? "This setting was armed in a different instance and copied here, so no tasks run automatically."
|
||||
: "This setting is missing its activation cutoff, so no tasks run automatically."}{" "}
|
||||
Toggle it off and back on to arm execution for tasks created here.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</Card>
|
||||
) : null}
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Server Info Debug View"
|
||||
description='Show a "Server" section in the account drawer with the current server restart time and running commit.'
|
||||
checked={enableServerInfoDebugView}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableServerInfoDebugView: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableServerInfoDebugView}
|
||||
ariaLabel="Toggle server info debug view experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Smoke Lab"
|
||||
description='Add a "Smoke Lab" tab under Apps → Developer and an "Integration smoke" card on the dashboard for exercising every integration path against deterministic local fixtures (fake OAuth provider + loopback MCP servers). Private (non-public) deployments only.'
|
||||
checked={enableSmokeLab}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableSmokeLab: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableSmokeLab}
|
||||
ariaLabel="Toggle smoke lab experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Status Cards"
|
||||
description="Enable the experimental shared status-card board and its gated API. Existing card data is kept when this is disabled."
|
||||
footnote="Enabling Status Cards also enables Summaries."
|
||||
checked={enableStatusCards}
|
||||
onCheckedChange={(checked) =>
|
||||
toggleMutation.mutate(
|
||||
checked
|
||||
? { enableSummaries: true, enableStatusCards: true }
|
||||
: { enableStatusCards: false },
|
||||
)
|
||||
}
|
||||
disabled={toggleMutation.isPending || statusCardsBlockedByManagedSummaries}
|
||||
managed={managedKeys.enableStatusCards}
|
||||
ariaLabel="Toggle status cards experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Summaries"
|
||||
description="Show Summarizer-generated status slots on project and workspace pages, with on-demand refresh and revision history. Existing summary data is kept when this is disabled."
|
||||
footnote="Status Cards requires Summaries. Disabling Summaries also disables Status Cards."
|
||||
checked={enableSummaries}
|
||||
onCheckedChange={(checked) =>
|
||||
toggleMutation.mutate(
|
||||
checked || !enableStatusCards
|
||||
? { enableSummaries: checked }
|
||||
: { enableSummaries: false, enableStatusCards: false },
|
||||
)
|
||||
}
|
||||
disabled={toggleMutation.isPending || summariesRequiredByManagedStatusCards}
|
||||
managed={managedKeys.enableSummaries}
|
||||
ariaLabel="Toggle summaries experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Task Plan Decomposition Panel"
|
||||
description="Show accepted-plan decomposition history on task detail pages. Intended for debugging and validating subtask creation behavior while the presentation is still being refined."
|
||||
checked={enableIssuePlanDecompositions}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableIssuePlanDecompositions: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableIssuePlanDecompositions}
|
||||
ariaLabel="Toggle task plan decomposition panel experimental setting"
|
||||
/>
|
||||
|
||||
<ExperimentalToggleCard
|
||||
title="Task Watchdogs"
|
||||
description="Show task detail controls for configuring watchdog agents that verify stopped task subtrees and restore live paths when work should continue."
|
||||
checked={enableTaskWatchdogs}
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({ enableTaskWatchdogs: checked })}
|
||||
disabled={toggleMutation.isPending}
|
||||
managed={managedKeys.enableTaskWatchdogs}
|
||||
ariaLabel="Toggle task watchdogs experimental setting"
|
||||
/>
|
||||
|
||||
{previewDialogOpen && !autoRecoveryManaged ? (
|
||||
<RecoveryPreviewDialog
|
||||
open
|
||||
|
|
|
|||
Loading…
Reference in New Issue