feat(demo): 'it's agents all the way down' scripted animation + Library as a toggleable panel#4327
feat(demo): 'it's agents all the way down' scripted animation + Library as a toggleable panel#4327vibegui wants to merge 34 commits into
Conversation
There was a problem hiding this comment.
8 issues found and verified against the latest diff
You’re at about 95% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/mesh/src/web/layouts/org-shell-layout/index.tsx">
<violation number="1" location="apps/mesh/src/web/layouts/org-shell-layout/index.tsx:146">
P2: The LibraryPanel can render alongside the full `/$org/files` route content when the panel was previously left open. Since `libraryOpen` is persisted in localStorage, visiting `/$org/files` (via deep link or navigation) while the panel state is `true` shows two Library instances reading/writing the same `?path=` and `?preview=` URL params. Consider either closing the panel when the route is already `/$org/files`, or checking the current route to skip the panel render on that route.</violation>
</file>
<file name="apps/mesh/src/web/components/sidebar/task-groups/agent-row.tsx">
<violation number="1" location="apps/mesh/src/web/components/sidebar/task-groups/agent-row.tsx:60">
P2: Keyboard reordering can stop working in expanded agent rows because the row-level `onKeyDown` replaces dnd-kit’s sortable key handler. Composing `sortable.listeners.onKeyDown` before the open-on-Enter/Space logic keeps drag keyboard support and avoids regressing accessibility.</violation>
</file>
<file name="apps/mesh/src/web/demo/runner.ts">
<violation number="1" location="apps/mesh/src/web/demo/runner.ts:27">
P1: Unexpected errors in scenario scripts silently cause a hang. The bare `catch{}` block swallows all errors, not just abort rejections. When a non-abort error (e.g., a TypeError in scenario code) is thrown inside `scenario.run()`, the catch falls through to `markEnded()` and then `awaitReplay()`, which waits indefinitely for a replay click that will never come in a broken state — the function's promise never resolves.</violation>
</file>
<file name="apps/mesh/src/web/demo/ghost-cursor.tsx">
<violation number="1" location="apps/mesh/src/web/demo/ghost-cursor.tsx:36">
P3: The cursor SVG and click ripple are purely decorative demo elements that should be hidden from assistive technology. Add `aria-hidden="true"` to each decorative element so screen readers skip them during the animation.</violation>
</file>
<file name="apps/mesh/src/web/components/sidebar/task-groups/team-threads-section.tsx">
<violation number="1" location="apps/mesh/src/web/components/sidebar/task-groups/team-threads-section.tsx:78">
P2: Users on touch/mobile can miss navigation to the full Threads monitor when team thread count is small, because the only fallback button is hidden behind `hasOverflow`. Consider rendering a visible in-list "See all" action even without overflow (or making the header action always visible on touch).</violation>
</file>
<file name="apps/mesh/src/web/demo/stage.tsx">
<violation number="1" location="apps/mesh/src/web/demo/stage.tsx:104">
P2: An empty `scenarios` input currently crashes the demo stage during render, even though the runner is written to no-op for empty arrays. This comes from the non-null assertion on `pinnedScenarios[0]` before reading `active.Stage`; adding a local null guard keeps behavior consistent and avoids a hard crash.</violation>
</file>
<file name="apps/mesh/src/web/demo/demo-chat-stream.tsx">
<violation number="1" location="apps/mesh/src/web/demo/demo-chat-stream.tsx:31">
P2: Chat message rendering can do extra work during the scripted animation because the provider `value` gets a new object identity on every parent render. Memoizing the context value by `state` keeps consumer re-renders tied to actual chat-store updates instead of unrelated shell updates.</violation>
</file>
<file name="apps/mesh/src/web/components/sidebar/task-groups/sidebar-section-header.tsx">
<violation number="1" location="apps/mesh/src/web/components/sidebar/task-groups/sidebar-section-header.tsx:28">
P2: Both buttons are missing the `focus-visible:ring-2 focus-visible:ring-ring/50` class that every other interactive element in the sidebar uses. Without it, keyboard users see no visible focus indicator — the outline is removed and no ring replaces it, breaking the established accessibility contract in this directory.</violation>
</file>
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
| // Let the layout mount before the first beat writes to its stores. | ||
| await director.wait(300); | ||
| await scenario.run(director); | ||
| } catch { |
There was a problem hiding this comment.
P1: Unexpected errors in scenario scripts silently cause a hang. The bare catch{} block swallows all errors, not just abort rejections. When a non-abort error (e.g., a TypeError in scenario code) is thrown inside scenario.run(), the catch falls through to markEnded() and then awaitReplay(), which waits indefinitely for a replay click that will never come in a broken state — the function's promise never resolves.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/demo/runner.ts, line 27:
<comment>Unexpected errors in scenario scripts silently cause a hang. The bare `catch{}` block swallows all errors, not just abort rejections. When a non-abort error (e.g., a TypeError in scenario code) is thrown inside `scenario.run()`, the catch falls through to `markEnded()` and then `awaitReplay()`, which waits indefinitely for a replay click that will never come in a broken state — the function's promise never resolves.</comment>
<file context>
@@ -0,0 +1,34 @@
+ // Let the layout mount before the first beat writes to its stores.
+ await director.wait(300);
+ await scenario.run(director);
+ } catch {
+ if (signal.aborted) return;
+ }
</file context>
| </div> | ||
| </SidebarInset> | ||
| {!isMobile && ( | ||
| <LibraryPanel |
There was a problem hiding this comment.
P2: The LibraryPanel can render alongside the full /$org/files route content when the panel was previously left open. Since libraryOpen is persisted in localStorage, visiting /$org/files (via deep link or navigation) while the panel state is true shows two Library instances reading/writing the same ?path= and ?preview= URL params. Consider either closing the panel when the route is already /$org/files, or checking the current route to skip the panel render on that route.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/layouts/org-shell-layout/index.tsx, line 146:
<comment>The LibraryPanel can render alongside the full `/$org/files` route content when the panel was previously left open. Since `libraryOpen` is persisted in localStorage, visiting `/$org/files` (via deep link or navigation) while the panel state is `true` shows two Library instances reading/writing the same `?path=` and `?preview=` URL params. Consider either closing the panel when the route is already `/$org/files`, or checking the current route to skip the panel render on that route.</comment>
<file context>
@@ -125,7 +142,19 @@ export default function OrgShellLayout() {
</div>
</SidebarInset>
+ {!isMobile && (
+ <LibraryPanel
+ open={libraryOpen}
+ onClose={() => setLibraryOpen(false)}
</file context>
| role="button" | ||
| tabIndex={0} | ||
| onClick={() => onOpen(virtualMcpId)} | ||
| onKeyDown={(e) => { |
There was a problem hiding this comment.
P2: Keyboard reordering can stop working in expanded agent rows because the row-level onKeyDown replaces dnd-kit’s sortable key handler. Composing sortable.listeners.onKeyDown before the open-on-Enter/Space logic keeps drag keyboard support and avoids regressing accessibility.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/sidebar/task-groups/agent-row.tsx, line 60:
<comment>Keyboard reordering can stop working in expanded agent rows because the row-level `onKeyDown` replaces dnd-kit’s sortable key handler. Composing `sortable.listeners.onKeyDown` before the open-on-Enter/Space logic keeps drag keyboard support and avoids regressing accessibility.</comment>
<file context>
@@ -0,0 +1,116 @@
+ role="button"
+ tabIndex={0}
+ onClick={() => onOpen(virtualMcpId)}
+ onKeyDown={(e) => {
+ if (e.target !== e.currentTarget) return;
+ if (e.key === "Enter" || e.key === " ") {
</file context>
| showAgentIcon | ||
| /> | ||
| ))} | ||
| {hasOverflow && ( |
There was a problem hiding this comment.
P2: Users on touch/mobile can miss navigation to the full Threads monitor when team thread count is small, because the only fallback button is hidden behind hasOverflow. Consider rendering a visible in-list "See all" action even without overflow (or making the header action always visible on touch).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/sidebar/task-groups/team-threads-section.tsx, line 78:
<comment>Users on touch/mobile can miss navigation to the full Threads monitor when team thread count is small, because the only fallback button is hidden behind `hasOverflow`. Consider rendering a visible in-list "See all" action even without overflow (or making the header action always visible on touch).</comment>
<file context>
@@ -0,0 +1,92 @@
+ showAgentIcon
+ />
+ ))}
+ {hasOverflow && (
+ <button
+ type="button"
</file context>
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, []); | ||
|
|
||
| const active = pinnedScenarios[activeIndex] ?? pinnedScenarios[0]!; |
There was a problem hiding this comment.
P2: An empty scenarios input currently crashes the demo stage during render, even though the runner is written to no-op for empty arrays. This comes from the non-null assertion on pinnedScenarios[0] before reading active.Stage; adding a local null guard keeps behavior consistent and avoids a hard crash.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/demo/stage.tsx, line 104:
<comment>An empty `scenarios` input currently crashes the demo stage during render, even though the runner is written to no-op for empty arrays. This comes from the non-null assertion on `pinnedScenarios[0]` before reading `active.Stage`; adding a local null guard keeps behavior consistent and avoids a hard crash.</comment>
<file context>
@@ -0,0 +1,121 @@
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const active = pinnedScenarios[activeIndex] ?? pinnedScenarios[0]!;
+ const ActiveStage = active.Stage;
+
</file context>
| }: PropsWithChildren<{ store: Store<DemoChatState> }>) { | ||
| const state = useSyncExternalStore(store.subscribe, store.get, store.get); | ||
|
|
||
| const value: ChatStreamContextValue = { |
There was a problem hiding this comment.
P2: Chat message rendering can do extra work during the scripted animation because the provider value gets a new object identity on every parent render. Memoizing the context value by state keeps consumer re-renders tied to actual chat-store updates instead of unrelated shell updates.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/demo/demo-chat-stream.tsx, line 31:
<comment>Chat message rendering can do extra work during the scripted animation because the provider `value` gets a new object identity on every parent render. Memoizing the context value by `state` keeps consumer re-renders tied to actual chat-store updates instead of unrelated shell updates.</comment>
<file context>
@@ -0,0 +1,56 @@
+}: PropsWithChildren<{ store: Store<DemoChatState> }>) {
+ const state = useSyncExternalStore(store.subscribe, store.get, store.get);
+
+ const value: ChatStreamContextValue = {
+ messages: state.messages,
+ status: state.status,
</file context>
| type="button" | ||
| aria-expanded={open} | ||
| onClick={onToggle} | ||
| className="flex flex-1 min-w-0 items-center gap-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/80 hover:text-foreground transition-colors focus-visible:outline-none" |
There was a problem hiding this comment.
P2: Both buttons are missing the focus-visible:ring-2 focus-visible:ring-ring/50 class that every other interactive element in the sidebar uses. Without it, keyboard users see no visible focus indicator — the outline is removed and no ring replaces it, breaking the established accessibility contract in this directory.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/sidebar/task-groups/sidebar-section-header.tsx, line 28:
<comment>Both buttons are missing the `focus-visible:ring-2 focus-visible:ring-ring/50` class that every other interactive element in the sidebar uses. Without it, keyboard users see no visible focus indicator — the outline is removed and no ring replaces it, breaking the established accessibility contract in this directory.</comment>
<file context>
@@ -0,0 +1,52 @@
+ type="button"
+ aria-expanded={open}
+ onClick={onToggle}
+ className="flex flex-1 min-w-0 items-center gap-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/80 hover:text-foreground transition-colors focus-visible:outline-none"
+ >
+ {open ? (
</file context>
| transition: "transform 200ms ease-out, opacity 200ms ease-out", | ||
| }} | ||
| /> | ||
| {/* pointer */} |
There was a problem hiding this comment.
P3: The cursor SVG and click ripple are purely decorative demo elements that should be hidden from assistive technology. Add aria-hidden="true" to each decorative element so screen readers skip them during the animation.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/demo/ghost-cursor.tsx, line 36:
<comment>The cursor SVG and click ripple are purely decorative demo elements that should be hidden from assistive technology. Add `aria-hidden="true"` to each decorative element so screen readers skip them during the animation.</comment>
<file context>
@@ -0,0 +1,57 @@
+ transition: "transform 200ms ease-out, opacity 200ms ease-out",
+ }}
+ />
+ {/* pointer */}
+ <svg
+ width="22"
</file context>
Add a public, fully-mocked walkthrough that drives the REAL Studio chat components from a recorded stream — no backend, MCP transport, or auth. Framework (apps/mesh/src/web/demo/): - Director: a non-React class that owns all timing via @decocms/std sleep and mutates external Stores; components subscribe via useSyncExternalStore, so no useEffect is needed to animate. Screenplays read as a storyboard (await d.user/stream/think/tool/parallel/endTurn) and support multiple parallel chat tracks plus org switching, previews, a ghost cursor, and a typed terminal. - Chat seam: DemoChatStreamProvider supplies a scripted ChatStreamContextValue (via an exported DemoChatStreamContext) so the real renderers paint it identically to a live stream. - DemoProviders: mock ProjectContext + a network-free QueryClient. Two demos, each on its own URL (/demo chooser, /demo/<id>), light mode: - /demo/storefront — business user drops in a URL and gets an accurate perf+SEO diagnosis scorecard, a fix plan, parallel fixes, and a re-audit. - /demo/agents — Studio as a web Conductor: ghost cursor opens the connect- desktop modal, a mocked iTerm runs `bunx decocms link` then minimizes to "connected", then work runs across two orgs in parallel (chat + live preview) while switching context. The autoplay runner is guarded by a per-stores singleton with deferred teardown so the dev runtime's spurious effect re-runs can't restart a scenario mid-play. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reworked the scripted demos for rhythm and a real ending.
- Pacing: deliberate beats with anticipation captions, reading holds after
big content (diagnosis / result tables), staggered parallel fixes, and
smoother typing speeds.
- Transitions: caption fade/slide, org-workspace crossfade on switch, preview
iframe fade-in on change, and cursor-driven org switching (the ghost cursor
glides to and clicks the org tab) instead of hard cuts.
- Ending: the demo no longer loops silently — after a full play-through it
shows an end card ("Get started free" / "Watch again"). The runner plays
once, then awaits a replay signal.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Storefront demo: - The agent now proposes a real WORK PLAN inline in the chat — a sprint of task cards — and waits for the viewer to approve (ghost cursor clicks "Approve & start"). Tasks then tick live; the first deliverable is a pull-request card (checks → merge), then deploy + re-audit. - Ends with a "get this every morning" card to connect Slack / Teams for a daily automated audit. - Inline cards render via a tiny part-renderer registry (chat/message/parts/extra-part-renderers.ts) the demo registers into — the core chat renderer stays demo-agnostic (empty registry in normal use). Agents demo: - Replaced the top org tabs with a real Studio-style sidebar of agents. You switch agents from the sidebar; background work keeps running and a notification dot appears on an agent's icon when its task finishes. Fix: card outputs are replaced immutably on each update so the compiler-memoized cards actually re-render (in-place mutation was silently dropped). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…crumb, your-deco home, share-a-scope One continuous scripted walkthrough of the simplified navigation model: path = context. Breadcrumb (deco > org > agent) is the only nav and the chat's scope selector; org cards report as agents; every level has a Share that mints the MCP URL for exactly that scope. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…re beside breadcrumb The stage now copies the real shell's vocabulary: bg-sidebar cream body, card-shadow float cards, the home hero + capybara + corner art, the composer's Tools/scope/model chrome, colored tile avatars, real deco logo. Share moved from far-right to right beside the breadcrumb (it shares THAT scope). Library panel: give the floating card its cream backdrop + top breathing room so its rounded top isn't clipped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Home goes back to the vertical right rail — each org card now carries three metric squares (stat + delta, single-hue 12-point sparkline, watched number that updates live when work ships). Org agents also list directly under AGENTS in the home sidebar. Sparkline hues are the 700 steps of each org's hue, validated >=3:1 on the light surface. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wider canvas, bigger presence: larger metric values, taller squares, roomier cards. The orgs are the home's co-protagonist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Home sidebar carries example my-threads; the org sidebar gets the full Team threads / My threads / Agents structure with teammate attribution — you can see what teammates are working on in each org, and the demo points at it. The morning brief now ends with an inline 'Vela Store needs you' card whose button navigates into the org, landing in a thread where the pilot has already asked the question — you answer and work proceeds. New generic showCard primitive on the Director. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…th status chips; breadcrumb icons per level The guiding caption moves to the top (was lost over the composer), grows, gains backdrop blur and a violet tint — it reads as the narrator, not a product component. The org CTA card gets a real app-UI body: status chips (Assets approved ✓ / QA passed ✓ / Hero not shipped) beside the navigate button. Every breadcrumb level now carries its own icon tile, not just the deco logo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ecomes a sales question Nobody asks their teammate to 'keep LCP under 1.5s' — and the site shouldn't ship slow in the first place. Vela's pilot now audits before deploying, catches the regression the new hero introduced, subtasks Storefront Bot to fix it, then continues to deploy — the user only says 'ship it'. The agent-level zoom is now Store Ops with a question a human actually asks: how were yesterday's sales? (orders/revenue/AOV recap, drop converting at 2.1x). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s, explorable end state
Every assistant turn now carries its speaker (avatar tile/logo + name)
via Track.setSender. Settings becomes what the model says it should be:
an AGENT — always the bottom one in / and /{org} — whose screens are
MCP apps rendered in the preview panel ('Make Rafa an admin' → tool
call → the Members app updates). No special settings screen: chat +
preview, everywhere. The end card is dismissible into explore mode —
crumbs, agent rows, org cards and Share are genuinely clickable on the
final state, with floating Replay/Get-started pills.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… affordances, narration trial, cadence fixes Entering an org lands on its OPERATIONS dashboard (KPIs with anomaly flags, diagnosed anomalies, agent-proposed opportunities, review queue — after Rafael's mocks), not a site preview. Store Ops gets a sales app; the pilot's follow-ups land on a tasks kanban; Settings' Members app gains an invite box and 'Invite your team' pins to every sidebar. The CTA card now lands WITH the digest (no dead wait). Cadence fixes: the team-threads beat moves to after the ship (was an urgency-killing detour, and its display:contents target sent the ghost cursor to the top-left corner); Share moves to Store Ops (take THIS agent to WhatsApp); explore-mode clicks now set the right per-agent preview — fixes 'settings shows nothing'. Trial narration: two caption clips (macOS say, Samantha Enhanced) with a mute toggle on the caption row. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…y default The captions are now the narrator's script: 17 lines that lead the tale (present tense, written for the ear) instead of labeling UI. Every line has a Zoe (Premium) clip keyed by exact caption text. Narration is ON by default — the first pointer/keydown anywhere unlocks autoplay and re-speaks the line on screen; the toggle mutes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The show now opens with a start card — 'Play with narration' / 'Watch muted'. That click is the browser's audio unlock, so the FIRST line narrates (autoplay policy made cold-start narration impossible). Esc toggles a pausable clock: every Director/Track wait runs on chunked unpaused-time sleep (~150ms response), the in-flight clip pauses with it, and a pill says how to resume. Start/mute choices survive replays. Clips regenerated at 176wpm (186 was too fast). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ts pill changes Audited all 17 captions against clip durations: added a dashboard beat so line 5 completes, extended the two settings holds. Line 4 is now 'One brief, three orgs — and exactly one thing that actually needs you.' Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…o fit Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
caption() is now duration-aware: it awaits the previous line's clip window (from an exported VO_MS table) before replacing it, so no narration is ever cropped — regardless of voice or rate. All visible 'org(s)' become 'team(s)' (narration, rail label, digest header, helper text, end card). Clips regenerated with Isha @160wpm. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…2wpm - Captions now behave like subtitles: auto-clear when their narration window ends (no more idle pills over long tool sequences) and a fixed 700ms metronome gap before the next line. Verified with a MutationObserver run: 10/16 transitions at ~250ms pill-free, none over ~2.5s. - Script pass: "your deco Studio", proactive morning line, pilot→agent everywhere, "team context" framing, positive triage line, closing "same intelligence, only the context changes". - Every agent is a LOOP over goals: new minified SLO card (SLI, target, error budget, trend) in the Store Ops app; caption 11 says it. - All 17 clips regenerated at Isha @182wpm; VO_MS from afinfo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces macOS `say` clips with Maya1 (Apache 2.0) generated on-device: LM on MPS, sampling + SNAC decode on CPU (works around two PyTorch MPS bugs). Voice designed by description; all 17 clips whisper-verified word-for-word. VO_MS from sample-accurate wav lengths; final beat extended so markEnded() no longer crops the closing line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Line 5 loses "nothing to rebuild"; line 15 ("Setup is one person's
job") removed entirely; logo line now "back home — to your agents".
- vo-09 re-taken (5.6s -> 4.1s, the slow read), vo-11 re-taken without
the mid-phrase pause (and whisper-verified "loop", not "looped").
- Clips renumbered to vo-01..16; all takes whisper-verified; cadence
re-measured end to end (every clip plays fully, ~250ms metronome).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Voice picked from a 3-way bake-off (Maya US female/male, Chatterbox). "No settings screens anywhere" line removed; clips renumbered vo-01..15, all whisper-verified (one slurred take re-rolled), beats retimed to the shorter reads, cadence re-measured end to end. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- PreviewFrame gains an app switcher (top right): the current screen is explicitly ONE MCP app of this agent among many. The kanban beat now CLICKS the Tasks chip; chips are clickable in explore mode too. - Kanban restyled to brand: column wells, white cards, brand chips, agent/human avatar rows. - Org/agent level split is chat 40 / preview 60. - Lines 1-2 re-taken cheerful (viewer-picked take B); line 1 is now "This is deco Studio — the home for your AI agents!" Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plain `2fr` tracks have min-width:auto — the reasoning row's long single line stretched the chat column over the preview. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New line 6: "Top left is your context" — the breadcrumb gets a violet
spotlight while it plays; the crumb is named as scope + agent selector.
- Share arc rebuilt: agent scope goes to "Claude Code, Codex, or
anywhere"; a new beat walks UP the breadcrumb and shares the whole
team as one MCP; back home, a new beat connects Claude to your deco
("all your teams at once"). Codex added to client chips.
- Kanban rebuilt with Studio's real tokens (warm neutrals, 6px radius,
ring-shadow cards) and story-connected tasks: the Winter Drop ship
sits in "Done · today", follow-ups mirror the sidebar team threads.
- Script is 18 lines; 4 new clips generated + whisper-verified (one
"Cloud Code" mispronunciation re-rolled); cadence verified end to end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Main added editQueuedMessage / removeLocalMessage / isSendInFlight to the live chat-stream contract; the scripted demo stream is read-only, so stub them (no queued-edit, no local removal, never in flight). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce `deco / <org> / <agent>` breadcrumb in the org-shell toolbar: - **deco** — logo, links to `/` (the cross-org MY-deco home, next commit). - **org** — opens the org switcher popover (reuses the org list UI, now extracted from account-popover into a shared `header/org-switcher`). - **agent**— the active agent, resolved from `?virtualmcpid`, inside a thread. The sidebar-footer AccountPopover keeps account/settings/logout; org switching now lives "up" in the breadcrumb. Replaces the bare Toolbar.LogoLink in the org shell (LogoLink still used by settings + sidebar logo header). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The root route is now the center of your work: every thread you own across
every org, as cards sorted by what needs you next (requires_action →
in_progress → … → done, then recency). No auto-redirect into your last org —
that's a click away via the breadcrumb or by opening any card.
- `useMyThreads` fans out COLLECTION_THREADS_LIST { created_by: "me" } per org
over each org's self-MCP client (reused from cache), merges + sorts client
side. Agents resolved per-org via COLLECTION_VIRTUAL_MCP_LIST so cards show
the agent without org context. No new backend tool, no migration.
- Org-less shell (own header + trimmed AccountMenu; no ProjectContextProvider).
- Org filter chips, per-org error isolation, loading skeletons, empty state.
- homeRoute moves under rootRoute; only zero-org users bounce to /onboarding.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each card now reads "what's happening here" from the thread's actual latest activity, not just its status: - Instant heuristic: the manager-oriented status verb (kept as a prefix). - Content summary: the latest agent message (or in-flight tool), pulled from COLLECTION_THREAD_MESSAGES_LIST over the org's self-MCP, cached per (threadId, updated_at). Fetched only for active threads so completed work doesn't fan out a message read. useThreadAnalysis is written with an explicit LLM-upgrade seam: swap the extractive summarizeMessages for a THREAD_ANALYZE backend tool (LLM_DO_GENERATE + a model from AI_PROVIDERS_LIST_MODELS) and the hook shape/caching are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f00259e to
8c41cca
Compare
…deco When you have no threads, MY deco now shows a chatbox instead of a dead-end. Pick an org (chips when you're in several), type, submit → it creates a fresh thread in that org and sends your message. Reuses the app's new-thread handoff verbatim: write the message to sessionStorage keyed by (locator, taskId) via writeStoredAutosend, then navigate to /$org/$taskId?autosend=true. The destination route's useEnsureTask creates the thread and the autosend consumer fires the first message — so no org-scoped context or ThreadManager is needed on the org-less home. Top filter chips now hide until there's something to filter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Superseding this with focused PRs (breadcrumb in #4473). Closing the demo PR. |
What is this contribution about?
A scripted, full-screen product animation of the "path = context" navigation model from #4326 — plus a real UX fix that fell out of building it (Library as a toggleable panel instead of a route).
1.
/demo/turtles— one animation instead of two demosReplaces the two previous demo scenarios with a single continuous walkthrough of the simplified world, built on the demo-mode Director/ghost-cursor machinery (rebased onto current
main) and rendered with the real chat pipeline and the real shell's design vocabulary (bg-sidebar cream, card-shadow float cards, the home hero + capybara + corner art, the composer's Tools/scope/model chrome, the real deco logo):ask_org_pilotto every org in parallel and streams a "While you were away" digest table with a Needs you column; the rail updates live.deco / Vela Store→ same product one level down: agents sidebar, chat with the org's pilot, live storefront preview. Ship a task; watch the storefront change.deco / Vela Store / Storefront Bot— fix LCP; the watched LCP square back on the home rail later ticks 1.9s → 1.2s.…/api/you/mcp,…/api/vela/mcp,…/api/vela/mcp/vela-bot) with client chips (Claude Code / Cursor / WhatsApp).The composer's scope chip changes with the breadcrumb (Decopilot → Vela Pilot → Storefront Bot) — breadcrumb = chat scope, made visible.
Also carries the sidebar thread-UX reorg (#4230: Team threads / My threads / Agents as collapsible peer sections), cherry-picked so both stories land together.
2. Library: a toggleable panel, not a route (real app change)
The Library sidebar item was a full route swap that destroyed your chat context. Now:
?path=— added to the chat route's search schema so it survives there)./$org/filesstays for deep links; mobile gets a full-screen sheet./filesroute keeps the side-by-side split where there's real horizontal space.Screenshots/Demonstration
Run
/demo/turtlesfor the animation. Frames verified headlessly at every beat (home rail with metric squares, digest table, org hop, agent zoom, share popover, end card) with zero console errors.How to Test
bun run dev, openhttp://localhost:4000/demo/turtles— the ~90s animation plays and loops via the end card./$org/filesstill renders the full split view.bun run check0 errors ·bun run lint0 errors ·bun run fmtapplied ·bun testunaffected (the 12 pre-existing env failures inmcp-oauth.test.ts/sidebar-release-card.test.tsxfail identically onmain).Migration Notes
/demo/storefront,/demo/agents) are replaced by/demo/turtles.Related: #4326 (the RFC this animates), #4230 (sidebar reorg, included), #3927 (demo mode, rebased + included).
🤖 Generated with Claude Code
Summary by cubic
Adds a public, full‑screen scripted demo mode with a
/demochooser and the “turtles” scenario, plus a new toolbar breadcrumb (deco › team › agent) that moves org switching up and turns/into a cross‑team “MY deco” home. Library becomes a toggleable panel you can open anywhere.New Features
/demoindex and/demo/turtlesplay a scripted walkthrough using the real chat viaDemoChatStreamContext, with a ghost cursor, narrated captions (15 Maya1 clips, on by default), and an end card (Replay/Get started). Inline cards render via a tiny part‑renderer registry (work plan, PR, daily digest, CTA). Per‑agent MCP apps (Ops dashboard with a compact SLO card, Sales, Tasks kanban, Settings → Members with invite) show in a preview pane with an app switcher; chat/preview split is 40/60.deco › team › agent) with a popover org switcher and Share beside it that mints scope‑exact MCP URLs (agent, team, or all teams up from the crumb)./becomes “MY deco” — your threads across all teams, sorted by what needs you next, with a compact account menu. Each card shows agent, status, last activity, and a content‑grounded “what’s happening here” line (fanned out per team via self‑MCP; cached). New empty‑state composer lets you start a thread in any team from home; it hands off to/$org/$taskId?autosend=trueand sends your message on arrival.?path=; preview takes over the narrow panel; proper aria/close in the Library header; mobile uses a sheet./$org/filesstays for deep links.Migration
/demo/storefrontand/demo/agentswith/demo/turtles(now listed at/demo)./is now the MY‑deco home (no auto‑redirect to last team); switch teams from the toolbar breadcrumb.Written for commit 4a0cfe3. Summary will update on new commits.
👋 @baby (Rafael Crespo) — continue here: the onboarding scenario
This PR has the day-30 demo (
/demo/turtles— morning brief, org hop, per-agent MCP apps, kanban, settings-as-agent, narration). Per our data-room meeting, the day-zero onboarding demo is yours — a second scenario on this same branch, so both play from/demo.Point your Claude at this PR and paste this prompt:
Everything's mocked and self-contained — no backend, no risk. Bring your dashboard HTML from the Baby-sandbox; the
orgDashboard()builder in turtles.tsx is already an adaptation of it, so lift whatever's missing.