feat(home): new home layout with SVG assets, tile board, and per-route panel state#3368
feat(home): new home layout with SVG assets, tile board, and per-route panel state#3368rafavalls wants to merge 49 commits into
Conversation
🧪 BenchmarkShould we run the Virtual MCP strategy benchmark for this PR? React with 👍 to run the benchmark.
Benchmark will run on the next push after you react. |
Release OptionsSuggested: Minor ( React with an emoji to override the release type:
Current version:
|
Adds an opt-in tile-based home board alongside today's chat-centric home. Users keep the existing simple home until they explicitly switch; once switched, the home becomes a 12-column snap grid where tiles can be added, dragged, resized to four presets (S/M/L/W), and removed. The board is per-user-per-org via localStorage today; the [board, setBoard] hook signature is intentionally sync-friendly so a future server backing store is a swap-in. Tile content is mocked end-to-end in this commit (12 tile types across essentials/activity/stats/shortcuts/data/workflow). Real plumbing for agent/MCP-contributed tiles will replace the static catalog in a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HomePage now reads the user's home board and renders either the existing simple home or the new TileBoard. A "Customize" button is portalled into Toolbar.Right; clicking it from simple mode opens an intro dialog (Stay simple / Start blank / Try the tile board), and from tiles mode toggles edit chrome (Add tile, Reset, Switch back to simple, Done). Mobile collapses to a stacked read-only view. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers the cases most likely to break under user input: compaction ordering, side-by-side packing, collision push-down, resize that displaces neighbours, x-clamping, and free-slot search. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Visual review against the rendered starter board showed: - Quick chat (L: 6×4) was too tall — textarea dominated empty space - Shortcuts buttons used aspect-square + small icons, wasting room - Workspace stats clustered at the top with empty space below - Connections preview icons were undersized (size-7) for an M tile - Welcome (W: 12×3) felt over-padded for a hero strip Changes: - Row height 96 → 80 px (tighter overall vertical rhythm) - L preset 6×4 → 6×3; W preset 12×3 → 12×2 (less vertical bloat) - Starter board snaps to 4/4/4 + 6/6 + 4/4/4 columns for clean alignment - Welcome: horizontal layout (text left, actions right) - Quick chat: tighter footer, send button h-7 - Shortcuts default size L (6×3), 2×2 grid that fills the tile - Stats: 2×2 cards that fill the tile, bigger numbers (text-2xl) - Connections preview icons size-7 → size-9 - Tile internal padding p-4 → p-3.5, gap-3 → gap-2.5 - Inter-tile gutter p-1.5 → p-1 for a tighter bento feel Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops the simple/tiles mode split. There is now one home: chat composer and agents strip render on top exactly as they do today, and a customisable tile board renders below that — but only when the user has at least one tile pinned. New users see today's home unchanged; power users get a dashboard that grows with them. - Removes the intro dialog and the "switch to simple / tiles" actions. - HomeBoard schema bumps to v2 and drops the `layout` field. v1 boards with empty tiles arrays migrate cleanly to empty v2 boards (which render identically to today's home). - Starter board now focuses on dashboard tiles only — drops Welcome, Quick chat, and Recent agents (those duplicate the top region). - Toolbar Customize button toggles edit mode for the tile area only; chat + agents are never edited. - Empty-state hint sits below the agents row when there are no tiles and the user isn't on the deco-import path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Top padding 10 → 16, post-greeting margin 8 → 10, agents-row gap 8 → 10, and 12 of margin / 10 of bottom padding around the tile board so it doesn't crowd the agents row above. Mirrors the same on mobile. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Earlier "tighten bento" pass overshot — tiles felt cramped. Brings back: - Row height 80 → 96 px - Inter-tile gutter p-1 → p-1.5 - Tile internal padding p-3.5 → p-4 (gap-2.5 → gap-3) - Tile header icon size-5 plain → size-6 with bg-muted - Card border tone border/80 → border (back to full opacity) Keeps the structural improvements that helped (Welcome horizontal hero, Stats 2×2 chips, Shortcuts default L, Connections size-9 preview icons) — those weren't the problem. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Desktop pt-16 → pt-24 (96px), mobile pt-16 → pt-20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop the "Mock" badge and the unused Badge import — tiles speak for themselves; mocked sources are still labelled in the catalog - Tighten icon→title gap (gap-2 → gap-1.5) and drop the muted-bg square behind the icon — leans on the title weight, not chrome - TileFrame padding p-4 → p-5 and gap-3 → gap-4 across the board - Recent tasks + Linear issues use a hairline divider per row instead of a flat list, with rounded-full pill status chips - Stats / Connections sub-cards rounded-md → rounded-lg, py-2 → py-3 - Shortcuts buttons p-3 → p-4, gap-2 → gap-3 (more breathing room inside each shortcut card) - Calendar items gap-2 → gap-3, dot mt-1 → mt-1.5 to align with title - Quick chat inner gap-2 → gap-3 - Welcome hero p-5 → p-6, gap-1 → gap-2 between header chip and title Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- TileFrame inner gap-4 → gap-5 (16 → 20px) so the title clearly separates from the content beneath it - Starter board: swap the GitHub/Linear/Calendar row with the Notes/Shortcuts row so the wide L+L pair sits in the middle — narrow rows above/below frame a wider centerpiece, which reads more bento than three same-sized rows in a row Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tiles felt boxy and noisy. Pivots to a quieter "feels-tappable" card with chromeless content: - Tile cards: bg-muted/30 (no border) replaces bg-background + border. In edit mode they get a visible border that pops on hover. Rounds bumped rounded-[0.75rem] → rounded-2xl. - Header icon: muted-bg square gone — replaced with a small bordered bg-background container, slightly smaller title (13px) with tight tracking. Less visual weight, more readable. - Stats: drop the chip cards. Each stat is just typography — large tabular-nums value + colored delta (emerald up / rose down / muted flat) + small muted label below. - Connections overview: same treatment — Active/Inactive/Errors as three clean stat columns with colored dots; preview icons sit in bg-background mini chips. - Recent tasks: drop dividers + pills. Each row is a colored status dot + title + muted status label aligned right. - Linear issues: drop chip backgrounds; ID becomes a colored mono label inline with the issue title. - GitHub activity: drop dividers; tighter line-spacing. - Calendar: time on the left as fixed-width tabular muted label, title aligned baseline — reads like a real schedule. - Notes: textarea gets a real bg-background card so it's clearly editable inside the muted tile. - Shortcuts: each shortcut is a bg-background card with a soft border that pops to primary on hover. - Page: agents → tiles gap mt-12 → mt-20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 12-col grid was too granular for the bento — sizes ended up as fractions of fractions and tiles felt small. Collapses the grid to 3 columns max with five named sizes that read like real bento blocks: S 1×1 small square M 1×2 single column, double tall (lists) L 2×1 landscape (charts, dual-pane) XL 2×2 chunky square (hero charts) W 3×1 full-width strip (banners) Row height jumps 96 → 200 px so a 1×1 is a real card. v2 boards auto-migrate: tile x and w are scaled by 1/4, h capped at 2 (was 3). The previous starter's M/L/W tiles map cleanly to the new presets. Adds the Reliability Agent tile (`agent.reliability`) — a 14-day errors-over-time area chart with today's count, delta vs yesterday (emerald if down, rose if up), and the running total. Default size XL; supports L / XL / W. Lives in the new "agent" source category so we can attribute later contributions. Starter board: Recent tasks (1×2) | Reliability Agent (2×2) Connections (2×1) | Stats (1×1) GitHub (1×1) | Linear (1×1) | Today (1×1) Tests rewrote to use the new 1–3 col widths and 1–2 row heights. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three customise-mode UX issues were dragging the experience down: 1. Drag preview was the wrong size. The DragOverlay used 100cqw, but it portals to document.body so container queries don't resolve — tiles ended up squished. We now capture the live cellWidth and cellHeight from the board element on drag start and feed absolute pixels (minus the inter-tile gutter) to DragOverlay so the dragged tile stays the same size as the source. 2. Edit mode now renders a real CSS-grid skeleton behind the tiles — 3 columns of dashed-border cells across the full board height — instead of a generic dot pattern. Users can see exactly where things will snap. Skeleton sits at z-0 and is pointer-events-none so it doesn't interfere with drag. 3. Dropping a tile on top of another now swaps them when the sizes match (clean visual exchange) and otherwise places the dragged tile at the occupant's anchor and slides the occupant downward — smoother than the old "always push down on collision" behaviour. Bonus: tiles transition left/top/width/height with a 200ms ease-out when neighbours reflow, so swap and resize feel cleaner. Transition is suppressed while a tile is actively being dragged so its pointer-following transform reads as immediate. Adds a unit test for the same-size swap path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously the edit-mode skeleton drew a 1×1 dashed rect at every (x, y) cell, including cells already covered by a tile. Because tiles have bg-muted/30 (translucent), the skeleton's inner divider lines bled through tall tiles like a 1×2 Workspace stats — looking like the tile contained two stacked cards. The fix is to compute which cells are covered and skip them. The skeleton is now exactly the set of empty drop targets, aligned to the same coordinate system as tiles so they visually match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two issues, one critical:
1. Rendered more hooks than during the previous render (crash).
BoardTile invoked the tile renderer as `def.render(props)` — a plain
function call. That folds the renderer's hooks into BoardTile's hook
tally. Different tile types have different hook counts (Reliability
uses useId, Welcome uses useState + useSession, etc.), and any time
re-render flow caused a transient mismatch the tally drifted and
React threw. Renderers now mount as real components — `<Renderer
instance={tile} isEditMode={...} />` — so each renderer's hooks
live in its own fiber boundary. Same fix in registry's
renderTileContent helper, which the mobile view + DragOverlay use.
2. Couldn't drop a tile into a far-away empty cell. moveTile piped
through compactBoard, which floats every tile up to row 0 — so a
tile dropped at row 5 instantly snapped back to row 0. Compaction
is removed from move/insert/resize/remove. The user's chosen layout
is preserved. Collisions still resolve (push-down for non-matching
sizes; clean swap for same-size occupants), but only the affected
tiles move.
Test for "remove leaves the gap" updated to match the new behaviour.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two small but visible tweaks: - Row height 200 → 240 px so a 1×1 reads as a real card (~7:4 instead of ~17:8). 1×2 is now 240×480 and 2×2 is 854×480 — proportions closer to what a dashboard card should feel like. - Every tile in the catalog now declares M (1 col × 2 rows) as a supported size — Stats, Connections, Shortcuts, Reliability Agent, Analytics Chart, and Quick chat were missing it. The size dropdown now surfaces a "Tall" option on tiles where it previously didn't appear. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds agent.app-frame, a tile that uses TileFrame's standard header (icon + title + optional action) and below that renders an iframe with smaller padding (-mx-3 -mb-3 against TileFrame's p-5) so the embedded view feels like an inset surface, not a paragraph of text. The iframe is sandbox="" (no scripts, no same-origin, no forms), with a srcDoc-embedded mock of a "Stripe payments" dashboard — KPIs and recent charges. Theme-aware via prefers-color-scheme so it reads correctly in light and dark. Purpose: a placeholder for the MCP-app contribution path. When apps ship their own tiles, they'll plug into the same TileFrame header and render their own UI inside the iframe slot. This commit proves the chrome split (header padding ≠ content padding) and the sandboxed embedding model. Catalog category: data; supported sizes M/L/XL/W (default XL). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Last refactor removed compaction everywhere so the user could place tiles wherever they dropped — but that left big vertical gaps when a single tile was dragged to the bottom of the board. Restore compaction as the default "tidy up" pass after every move/insert/ resize/remove. The same-size swap path still skips compaction (its result is gap-free by construction), so dropping one M tile on top of another reads as a clean exchange instead of both floating to the top. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Desktop pt-24 → pt-40 (96 → 160 px), mobile pt-20 → pt-28 (80 → 112 px). With the reduced number of tiles in the new starter and the taller cells, the chat area was sitting too high; this brings it down so the greeting + composer + agents read as a centered hero above the board. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The agents row below the chat used a different visual language from the tile board — small icon-on-top buttons in a 100px slot with no chrome. Now each agent (and the Create / See all buttons) renders as a 136px-wide card matching the bento system: rounded-2xl, bg-muted/30 with hover state, transparent border that pops on hover, p-4 padding, icon top-left, label below at text-[13px] tracking-tight. The row gap goes 1.5 → 2; max-h drops 52 → 32 so only one card-row shows on desktop. Skeleton matches the new shape. Net effect: chat → agents → tile board reads as one coherent visual language down the page instead of three different design eras. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promotes agents from the row above the chat into the tile board so the home is one design system end-to-end. - New AgentCardTile renderer. No iframe, no view — just a clickable card with icon, title, and description that navigates to a fresh chat thread (passing virtualmcpid so the chat surface knows which agent to wire up). - TileDefinition gains a `defaultConfig` field. Catalog entries can bake config (templateId / title / icon / description) into the instance the user adds. - Catalog registers one entry per WELL_KNOWN_AGENT_TEMPLATES under a new "Agents" category so users can pin specific agents from the Add-tile sheet. - Starter board seeds three agent cards (Site Editor, Image Creator, Web Researcher) sandwiched between the dashboard tiles. - AgentsList row removed from the home — chat sits directly above the tile board now. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two changes to make agents feel alive when they show up on the home: - Agent cards move to row 0 of the starter board so the very first thing the user sees below the chat is "what my agents are working on". Three cards across at M (1×2) so they're properly readable. - AgentCardTile now renders a list of recent tasks (mocked today, wired to live agent activity later) when the tile has vertical room (h ≥ 2). Each task is a colored status dot + truncated title; status colors match the design language used elsewhere (primary / amber / rose / emerald). When the agent has no tasks, the card falls back to its description. - Catalog seeds mock task lists for Site Editor, Site Diagnostics, Image Creator, and Self-healing Storefront so the catalog preview reflects what the card will look like once added. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two issues with the catalog drawer:
1. The ScrollArea sat inside a flex-1 wrapper without min-h-0, so in
a flex-col parent it kept its content-height and never actually
scrolled past the visible area. Wrap it in a `flex-1 min-h-0`
container so the inner ScrollArea root gets a definite height and
the content scrolls to the bottom — including the agents and the
workflow categories that were previously cut off.
2. Visual refresh:
- Header gets a tighter, smaller title + subtitle and a focused-on-
open search input.
- Each catalog row is now a 10×10 icon container in a soft card
with hover state (border-primary/40, bg-muted/40), 13px
tracking-tight title, 12px muted description.
- Source badge moves from outline to a colored pill (primary tint
for agents, amber for MCP) so the catalog reads at a glance.
- Category headers use a small uppercase-tracking-wider treatment
with a count chip on the right.
- Spacing between sections gap-6 → gap-7, page bottom padding
bumped so the last group doesn't sit flush against the edge.
Agents already lived in the catalog (registered in TILE_CATALOG via
AGENT_CARD_ENTRIES); they now appear visibly in the "Agents" section
near the top of the sheet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Strips every mocked tile and wires the kept ones to real Studio sources:
- RecentTasksTile reads from useTasks({ owner: "me", status: "open" })
and now reuses lib/task-status.ts (getStatusConfig) for icon/label/
color instead of a hand-rolled status map. Same surface as the
tasks panel so a status update drifts in one place, not two.
- RecentAgentsTile reads from useVirtualMCPs() and uses AgentAvatar
(the canonical agent visual used by the sidebar and tasks panel)
instead of IntegrationIcon. AgentCardTile too.
- StatsTile counts active agents, total agents, active connections,
and errored connections from the same hooks.
- Removed renderers: GithubActivityTile, LinearIssuesTile,
CalendarTile, AnalyticsChartTile, ReliabilityAgentTile,
AppFrameTile — all mock-only.
- Studio data tiles (recent-tasks, recent-agents, connections-
overview, stats) attributed to source: "agent", sourceId:
"studio-agent" via a shared STUDIO_AGENT_SOURCE constant.
Cleanup from review:
- Shared agent seeds (title/icon/description) moved to agent-seeds.ts
and consumed by both registry and starter so the catalog preview
stays in sync with placed instances.
- agentCardType(id) helper replaces inline `agent.card.${id}`
template strings.
- TileSlot component encapsulates the TileErrorBoundary + Suspense +
renderer-or-helper triplet that lived in three places (BoardTile,
mobile view, DragOverlay).
- Magic numbers extracted: RECENT_AGENT_LIMIT, RECENT_TASK_LIMIT,
CONNECTION_PREVIEW_LIMIT.
Each tile renders inside a Suspense fallback'd by TileSkeleton, so
slow Studio queries only block their own tile, not the whole board.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Category headers and the size pill in the catalog were rendered uppercase. Removed the uppercase + wide-tracking treatment so they match the rest of the design system (sentence case, tracking-tight). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The composer at the top of the home already covers this surface; duplicating it as a pinnable tile added a second textarea with the same destination. Drops the renderer, the catalog entry, and the Lightning01 / useState imports they were the only consumers of. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Studio's data tiles (Recent tasks, Recent agents, Connections,
Workspace stats) now wear the same agent-card chrome as the
template tiles: avatar top-left, agent name as a small muted
eyebrow, view name as the primary title, body below. Defines a
STUDIO_AGENT identity (Stars01 / violet) so all four read as views
of one agent.
- New AgentTileFrame: avatar + optional action chip on top, eyebrow
(agent name) + title (view name) below, body fills the rest.
- AgentCardTile reuses the same frame with eyebrow={false} so it
doesn't render "Image Creator / Image Creator" — title is the
agent name, body is the description, layout matches.
- System tiles that don't belong to an agent (Notes, Shortcuts,
Unknown) keep a slimmer SystemTileFrame with the small icon +
inline title — no avatar, no eyebrow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…it modals
Two regressions from the migration to tiles-only home:
1. New users landed on an empty board with a "Pin tiles to your home"
banner instead of the default tile set. The home is supposed to
start populated. useHomeBoard's first-load path (no localStorage
value) now seeds with createStarterBoard() instead of an empty
board. Boards explicitly cleared by the user (tiles: []) are
respected and stay empty.
2. Agent-card clicks were going straight to a fresh chat thread with
?virtualmcpid=<templateId>, but unrecruited templates have no live
vMCP — the chat surface spun on "starting task". Restores the
original AgentsList click logic via a new AgentRecruitProvider
that mounts every recruit/import modal once at the home and
exposes openAgent(templateId). AgentCardTile dispatches:
- site-editor → ImportFromDecoDialog
- site-diagnostics / ai-image / ai-research / lean-canvas →
their RecruitModal, OR navigate to the existing matching vMCP
when one is already installed (via useNavigateToAgentThread)
- studio-pack → StudioPackRecruitModal
- self-healing-storefront → SelfHealingRepoFlow
Custom (non-template) agent.card tiles still navigate directly.
HomePage wraps its content in AgentRecruitProvider so context is
available to every tile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ata tiles Two fixes per design feedback on the rendered home: - Agent cards in the starter board drop M (1×2) → S (1×1). At S the AgentTileFrame fits cleanly: avatar + name only, no description. The cards no longer dwarf the data tiles below them. - New AgentDataTileFrame for tiles attributed to an agent that have body content (Recent tasks, Recent agents, Connections, Workspace stats). Header is the same compact pattern SystemTileFrame uses — small AgentAvatar (xs/24px) inline with the view title — so the data area has maximum room. The big-avatar AgentTileFrame stays for agent.card tiles where the agent is the content. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two changes to the Add-tile sheet:
- New "Studio Agent" category renders Recent tasks, Recent agents,
Connections, and Workspace stats in their own group with the Studio
Agent avatar (xs Stars01/violet) on every row. Catalog rows now
render def.icon directly so the agent avatars look right inline —
the previous <img>-fallback wrapper is gone.
- Catalog goes from a static export to a useTileCatalog() hook. On
top of the static set it adds, for every active installed virtual
MCP:
- one agent-card entry pointing at the agent itself, and
- one tile per layout tab (`metadata.ui.layout.tabs`) and one per
pinned view (`metadata.ui.pinnedViews`)
When the user adds one of those UI tiles, AgentToolViewTile renders
it: an agent-attributed card that, on click, opens a thread with
?virtualmcpid=<agent>&main=<tab> so they land on the exact tab the
agent's settings layout would land on. Same `?main=` model the chat
surface already speaks.
- STUDIO_AGENT identity moved out of renderers.tsx into agent-seeds.ts
so the registry, the renderers, and any future consumer share the
same icon + name.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pinned dynamic tiles (one per installed agent and one per agent UI
view) carry a unique type like agent.tool-view.<id>.<tab> or
agent.card.installed.<id>. Those types aren't in the static
TILE_CATALOG, so after persistence + reload getTileDefinition
returned undefined and the board rendered UnknownTile ("Tile type X
isn't installed") even though the catalog had just generated it.
Add a prefix-matching fallback to getTileDefinition that returns a
minimal synthetic def for the two dynamic prefixes so TileSlot can
still route to AgentToolViewTile / AgentCardTile and the per-tile
size menu has supportedSizes to draw from. The instance's stored
config carries everything the renderer needs (agent id, title, icon,
mainTabId, etc.), so the synthetic def's title/description/icon
fields are intentionally empty.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The tool-view tile was a placeholder that said "Open the X view from
Y" — it didn't actually render the agent's UI. Now it embeds
AppViewContent (the same renderer the chat surface uses for layout
tabs and pinned views) so the agent's UI shows up directly in the
tile body.
Catalog wiring: dynamic tool-view entries now carry the resolved
(connectionId, toolName, args) on their defaultConfig so the renderer
can call the right tool without extra metadata lookups:
- layout tabs: connectionId = view.appId, toolName = tab.id,
args = view.args
- pinned views: connectionId = view.connectionId,
toolName = view.toolName
The `Open` action in the header still navigates to the full view in
the chat surface (?virtualmcpid=...&main=<tab>) for users who want
the fullscreen experience. Default size bumps L/XL/W with default XL
since the embedded UI needs room.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tool-view tiles pinned before connectionId/toolName were stored on
config still rendered the "Open <view>" placeholder because their
config carried only mainTabId. Add a resolveToolTarget helper that:
1. Returns config.connectionId/toolName when present (new pins).
2. Otherwise parses pinned-view tab ids of the form
`app:<connectionId>:<toolName>`.
3. Otherwise looks up the agent's live `metadata.ui.layout.tabs`
for a tab with id === mainTabId and reads view.appId / view.args.
AgentToolViewTile now calls useVirtualMCPs and feeds the resolved
target into AppViewContent, so an existing Monitor / pinned-view
tile renders its actual UI on the next reload — no re-pinning
required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The home tile system grew sprawling: 17 files, ~3.3k insertions, dnd grid, dynamic agent catalog, recruit provider, tile-add sheet, edit mode. Most was unused (`SHOW_HOME_TILES = false`) so the surface area never paid off. This rewrite collapses the system around the design intent: a side Tasks panel of preset cards that, on click, start a preconfigured chat and surface a matching tile on the home page once the work is running. - Tasks panel: 5 preset cards (New chat, Extract brand context, Create landing page, Set up error monitoring, Import Deco site) with colored thumbnail badges matching the Figma reference. New chat keeps its existing behavior; the three tile-producing presets call a small `startPresetTask` helper that primes autosend with a tailored prompt, activates the matching home tile, and navigates to the new thread. Import Deco opens the existing import dialog. - Home tiles: only three, mapped 1:1 to the three preset tasks (brand context, landing page, error monitoring). Responsive 1/2/3-column grid; each tile shows a running skeleton or a mock ready-state preview and clicks back to the chat that produced it. Activation persists per-org in localStorage. - Home page: chat composer untouched on top, tile grid below when activated. Added a subtle SVG-tile background pattern and the capybara peeking from the corner of the chat composer. - Deleted: agent-recruit-provider, agent-seeds, grid-utils +tests, tile-add-sheet, tile-config-update-context, tile-error-boundary, tile-slot, constants, seed, use-home-board. - Reverted: agents-list styling drift, localstorage key churn for removed tile-board/notes/pinned slots. Net change vs main: ~470 lines instead of 3.3k. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Course-correct from the over-aggressive cleanup. The dnd tile-board is back, the 5 side-panel task cards now use the Figma-exported PNG illustrations as their thumbnails, and the home page renders the real Figma background tile pattern. Tile system: - TileBoard with dnd-kit (drag, resize, remove, edit mode) restored. - Three preset tile types — studio.brand-context, studio.landing-page, studio.error-monitoring — each with its own renderer that flips between a running skeleton and a representative ready-state preview. Tiles carry the task id of the chat that spawned them so a click lands back in that thread. - Catalog shrunk to those three only; agent-recruit, dynamic agent catalog, agent-seeds, tile-add-sheet stay deleted. - start-preset-task primes autosend with the prompt and pins the matching tile to the user's board before navigating. Tasks panel: - Five preset cards: New chat, Extract brand context, Create landing page, Set up error monitoring, Import Deco site. Each renders the Figma PNG thumbnail (public/home/task-*.png) instead of a CSS recreation. Import Deco still opens the existing import dialog. - Clicking a tile-producing preset adds the matching tile to the home board via useHomeBoard.addTile and starts the chat. Home page: - Background uses the real Figma tile-pattern PNG, mirrored top/bottom. - Capybara peeks from the corner of the chat composer. - Customize toolbar (edit mode + clear) restored, gated to when the board has tiles. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nd wide sidebar - Replace all PNG home assets with SVG equivalents (crisp at any zoom, light/dark variants for background corners) - Redesign background: corner-anchored SVGs (top-left / bottom-right) instead of the tiled PNG strip - Fix scroll container so corner art stays fixed while content scrolls; vertically center input when no tiles are present - Tile icons now use IntegrationIcon + WELL_KNOWN_AGENT_TEMPLATES metadata (colored icon system) instead of hardcoded Untitled UI icons - Add brand-context / landing-page / system-health to WELL_KNOWN_AGENT_TEMPLATES - Bump tile drag-handle and menu-button to size-8 / icon-16 for larger hit targets - Tasks panel: remove empty-state; default to preset cards on home, task list in chat; per-route open/close state (home vs chat independent) - Wide sidebar mode (560 px) on home, normal (340 px) in chat routes - Preset cards: bordered style, h-11 w-16 thumbnails, numbered step badges - Fix chat input dark-mode background (bg-card instead of dark:bg-muted) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Format: split long function parameter in tasks-section.tsx - Lint: wrap ternary className with cn() in home-page/index.tsx - Knip: delete unused agents-list component, remove unused exports (MOBILE_BREAKPOINT_COLS, pixelDeltaToCellDelta, TILE_CATALOG export, useTileConfigUpdate) and unused function bodies Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…A25" This reverts commit 1509802.
- Transitioned to a 3-column grid layout with five preset tile sizes. - Removed unused tile types and related files, including tests and context providers. - Updated tile rendering logic to use a suspense boundary for better loading states. - Cleaned up constants and types, eliminating unnecessary properties. - Adjusted the home board logic to streamline tile management and initialization. This refactor focuses on enhancing maintainability and performance by reducing complexity in the tile system.
6dbfcfb to
8162aea
Compare
- Introduced a new `PresetTaskStore` for managing task states in KV storage. - Added `PresetTaskRegistry` to handle task definitions and their visibility. - Created API routes for preset tasks, including endpoints for starting and dismissing tasks. - Integrated brand-context workflow with DBOS for managing the lifecycle of brand-context tasks. - Updated the application context to include preset task dependencies. - Enhanced the home tile system to support new preset tasks, allowing users to initiate tasks directly from the UI. This implementation enhances the user experience by providing a structured way to manage and interact with preset tasks, improving overall functionality and maintainability.
…ynamic instructions - Added `brand-context` agent to manage brand setup and confirmation workflows, including functions to retrieve and update brand information. - Implemented `system-health` agent for monitoring site health, integrating with existing connection management. - Created `dynamic-instructions` registry to provide context-sensitive prompts based on organizational state. - Enhanced API routes to support new agents and their functionalities, including home board management and preset task integration. - Established a robust system for handling brand context and health monitoring, improving user experience and operational efficiency. This implementation lays the groundwork for more interactive and responsive agent behaviors, enhancing the overall functionality of the application.
There was a problem hiding this comment.
16 issues found across 63 files
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/agents/system-health.ts">
<violation number="1" location="apps/mesh/src/agents/system-health.ts:76">
P2: `ensureSystemHealthConnection` is not truly idempotent under concurrent calls; the check-then-create sequence can create duplicate system-health connections for one organization.</violation>
</file>
<file name="apps/mesh/src/web/components/home/tiles/tile-error-boundary.tsx">
<violation number="1" location="apps/mesh/src/web/components/home/tiles/tile-error-boundary.tsx:24">
P2: This error boundary never resets after a crash, so a tile can remain permanently stuck on the fallback until remount. Add a reset mechanism (for example, reset when a `resetKey` prop changes).</violation>
</file>
<file name="apps/mesh/src/agents/dynamic-instructions.ts">
<violation number="1" location="apps/mesh/src/agents/dynamic-instructions.ts:33">
P2: Use an explicit null check when resolving instructions; the current truthy check incorrectly ignores valid empty-string results.</violation>
</file>
<file name="apps/mesh/src/storage/home-board.ts">
<violation number="1" location="apps/mesh/src/storage/home-board.ts:123">
P1: `pickAutoPinSlot` has a hardcoded row cap and may return an unchecked occupied position once `y` reaches 1024.</violation>
</file>
<file name="apps/mesh/src/web/lib/query-keys.ts">
<violation number="1" location="apps/mesh/src/web/lib/query-keys.ts:89">
P2: `homeBoard` query key is missing a user dimension even though the cached data is per-user, which can cause cross-user cache reuse within the same org.</violation>
</file>
<file name="apps/mesh/src/tools/github/has-installation.ts">
<violation number="1" location="apps/mesh/src/tools/github/has-installation.ts:51">
P2: This check only inspects the first page of GitHub installations, so it can incorrectly return `false` when the matching org appears on later pages.</violation>
</file>
<file name="apps/mesh/src/web/hooks/use-auto-install-system-health.ts">
<violation number="1" location="apps/mesh/src/web/hooks/use-auto-install-system-health.ts:60">
P1: The start condition can permanently block auto-install when `org` is not ready on first render. Include `org` in the gate before setting `startedRef`.</violation>
</file>
<file name="apps/mesh/src/web/hooks/use-tasks-panel-state.tsx">
<violation number="1" location="apps/mesh/src/web/hooks/use-tasks-panel-state.tsx:34">
P2: `chatOpen` is derived from `tasks.length` only at initial mount, so route transitions after task-list changes can show the chat panel closed even when open tasks exist.</violation>
</file>
<file name="apps/mesh/src/api/routes/deco-sites.ts">
<violation number="1" location="apps/mesh/src/api/routes/deco-sites.ts:462">
P0: Hardcoded deco.cx email bypasses per-user identity and makes authorization/data lookups run as a fixed account.</violation>
</file>
<file name="apps/mesh/src/api/routes/decopilot/built-in-tools/brand-context-confirm.ts">
<violation number="1" location="apps/mesh/src/api/routes/decopilot/built-in-tools/brand-context-confirm.ts:140">
P1: Handle `extractBrandFromDomain` exceptions and return a structured tool error instead of letting the tool throw.</violation>
<violation number="2" location="apps/mesh/src/api/routes/decopilot/built-in-tools/brand-context-confirm.ts:195">
P2: Verify the organization still has a primary brand before marking the brand-context preset as completed.</violation>
</file>
<file name="apps/mesh/src/preset-tasks/brand-context-workflow.ts">
<violation number="1" location="apps/mesh/src/preset-tasks/brand-context-workflow.ts:74">
P2: Guard timeout/error writes so only the active workflow run can update preset state; otherwise stale workflows can overwrite newer run results.</violation>
</file>
<file name="apps/mesh/src/agents/brand-context.ts">
<violation number="1" location="apps/mesh/src/agents/brand-context.ts:54">
P1: Untrusted brand fields are injected into the system prompt without sanitization, enabling prompt-injection via extracted website content.</violation>
</file>
<file name="apps/mesh/src/api/routes/preset-tasks.ts">
<violation number="1" location="apps/mesh/src/api/routes/preset-tasks.ts:272">
P1: Require authentication on the dismiss route; it currently allows unauthenticated callers to modify org-scoped preset task state.</violation>
</file>
<file name="apps/mesh/src/api/app.ts">
<violation number="1" location="apps/mesh/src/api/app.ts:437">
P2: Token persistence misses client credentials sent via HTTP Basic auth, which causes stored tokens to be non-refreshable (`clientId` remains null).</violation>
<violation number="2" location="apps/mesh/src/api/app.ts:539">
P1: Persisting downstream tokens in the shared oauth-proxy handler allows token writes on the legacy unscoped path, which can bypass org-scoped authorization checks.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| const [homeOpen, setHomeOpen] = useState<boolean>(() => | ||
| onHome ? resolveTasksOpen(search.tasks, true) : true, | ||
| ); | ||
| const [chatOpen, setChatOpen] = useState<boolean>(() => |
There was a problem hiding this comment.
P2: chatOpen is derived from tasks.length only at initial mount, so route transitions after task-list changes can show the chat panel closed even when open tasks exist.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/hooks/use-tasks-panel-state.tsx, line 34:
<comment>`chatOpen` is derived from `tasks.length` only at initial mount, so route transitions after task-list changes can show the chat panel closed even when open tasks exist.</comment>
<file context>
@@ -12,27 +12,32 @@ interface TasksPanelState {
+ const [homeOpen, setHomeOpen] = useState<boolean>(() =>
+ onHome ? resolveTasksOpen(search.tasks, true) : true,
);
+ const [chatOpen, setChatOpen] = useState<boolean>(() =>
+ !onHome
+ ? resolveTasksOpen(search.tasks, tasks.length > 0)
</file context>
- Added a new `web-developer` agent that facilitates the creation of static HTML pages, allowing users to write, read, list, and delete pages stored in object storage. - Implemented dynamic instructions for the web-developer agent to provide context-sensitive prompts based on the user's brand information. - Created built-in tools for the web-developer agent, including `write_html_page`, `read_html_page`, `list_html_pages`, and `delete_html_page`, enhancing the agent's functionality. - Updated API routes to integrate the web-developer agent and its tools, ensuring seamless interaction within the application. - Enhanced the chat interface to support HTML page previews, improving user experience during page creation. This implementation expands the capabilities of the application by enabling users to generate and manage web content directly through the chat interface.
There was a problem hiding this comment.
1 issue found across 16 files (changes from recent commits).
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/api/routes/decopilot/built-in-tools/web-developer.ts">
<violation number="1" location="apps/mesh/src/api/routes/decopilot/built-in-tools/web-developer.ts:159">
P2: `list_html_pages` only returns the first 100 objects, so results become incomplete once a thread has >100 pages.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Introduced a `sanitizeBrandField` function to clean and limit the length of brand-related fields, improving data presentation. - Updated the `formatConfirmModePrompt` function to utilize the new sanitization logic for brand details. - Enhanced error handling in the brand extraction process, providing clearer feedback when extraction fails. - Added checks to ensure brand context exists before proceeding with confirmation workflows, improving robustness. These changes enhance the user experience by ensuring cleaner data display and more informative error messages during brand context operations.
There was a problem hiding this comment.
1 issue found across 6 files (changes from recent commits).
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/agents/brand-context.ts">
<violation number="1" location="apps/mesh/src/agents/brand-context.ts:50">
P1: `sanitizeBrandField` does not neutralize `<`/`>`, so untrusted brand content can inject `</brand>` and escape the protected block in the prompt. Escape angle brackets (and `&`) before interpolation.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
- Restore real auth checks in deco-sites.ts profile/list/connection routes; the dev-only hardcoded email was an oversight from local-auth debugging. - Remove OAuth-proxy downstream-token persistence and the supporting Basic-auth/form-body credential capture from app.ts; this is a separate concern from the home redesign and will be re-landed in its own PR. - Drop the rAF-coalesced streaming and finish-handoff dedupe from use-thread-chat.ts; same — chat-stream perf belongs in its own PR. - Drop the thread→virtual_mcp_id drift guard from dispatch-run.ts. - Revert the user-ask refactor (react-hook-form draft split + decoder helper + tests) so the home PR doesn't bundle that change. These pieces stay in the working tree for the author to land separately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…LoC)
Multi-perspective code review surfaced ~600 LoC of duplication and dead
indirection in the home redesign. This consolidates the easy wins.
Frontend
- Extract InstallFlowDialog shell + runOAuthHandshake helper; delete
install-{github,system-health}-dialog wrapper files and shrink both
auto-install hooks to their distinctive create-connection step.
- Delete the tile registry/TileDefinition indirection: there was one
TileDefinition for one tile type. TileSlot now renders <PresetTile/>
directly; supportedSizes falls through to ALL_SIZES.
mesh-sdk
- Add preset-tasks.ts module with PresetTaskAction/Status/State/Step,
VisiblePresetTask, StartPresetTaskResult, etc. Both FE and BE now
import from here, fixing real FE↔BE drift (FE was missing
dbosWorkflowId and steps fields).
- Extract createWellKnownAgentPrefix({prefix}) → {is, get} factory and
defineWellKnownAgentVMCP() helper for the 12-field entity envelope;
collapse 4 duplicate prefix pairs and 3 VirtualMCPEntity factories.
Backend
- Extract built-in-tools/brand-context-helpers.ts: requireOrgId,
requireFirecrawlKey, requireOrgBrand, brandSnapshot — replaces the
repeated 4-step auth/firecrawl/brand envelope across brand-context
setup and confirm tools.
- Delete agents/dynamic-instructions.ts registry. Direct calls to
resolveBrandContextPrompt / resolveWebDeveloperPrompt in dispatch-run
replace the side-effecting register/resolve pattern; the two boot-time
register* calls in app.ts go away.
- Add kvGet/kvSet helpers in storage/kv.ts so HomeBoardStore and
PresetTaskStore stop hand-rolling the same get/set + cast ceremony.
- Narrow several incidental exports to internal types
(BrandExtractedSignal, BrandContextWorkflow{Input,Outcome},
PresetBodyProps, PresetTaskStep, PresetTaskStepStatus).
No behavior changes. Typecheck, lint, and fmt pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s and connection management - Introduced `getSystemHealthAgentConnectionId` function to resolve the agent's connection ID, enabling automation setup. - Added `createSystemHealthTools` for creating health automation, allowing users to schedule recurring runs or subscribe to events. - Updated `ensureSystemHealthAgent` to include UI configurations for application errors. - Enhanced API routes to integrate system health tools, improving the agent's functionality and user experience. - Added tests for new user-ask response handling and schemas, ensuring robust input validation. These changes expand the capabilities of the system health agent, facilitating better monitoring and automation of site health checks.
There was a problem hiding this comment.
1 issue found across 32 files (changes from recent commits).
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/hooks/use-oauth-handshake.ts">
<violation number="1" location="apps/mesh/src/web/hooks/use-oauth-handshake.ts:87">
P2: `onPersistFallback` can run twice when the first fallback call throws, causing duplicate side effects.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
| ); | ||
| if (!response.ok) { | ||
| if (opts.onPersistFallback) { | ||
| await opts.onPersistFallback(connectionId, token); |
There was a problem hiding this comment.
P2: onPersistFallback can run twice when the first fallback call throws, causing duplicate side effects.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/hooks/use-oauth-handshake.ts, line 87:
<comment>`onPersistFallback` can run twice when the first fallback call throws, causing duplicate side effects.</comment>
<file context>
@@ -0,0 +1,108 @@
+ );
+ if (!response.ok) {
+ if (opts.onPersistFallback) {
+ await opts.onPersistFallback(connectionId, token);
+ } else {
+ const body = (await response.json().catch(() => ({}))) as {
</file context>
Tip: Review your code locally with the cubic CLI to iterate faster.
What is this contribution about?
Redesigns the home page with a new tile board system, SVG decorative assets (replacing PNGs, with light/dark variants), and a per-route tasks panel state. The tasks panel now defaults open on home (wide 560 px) and independently tracks open/close state from the chat routes. Preset cards in the tasks panel get a bordered style with numbered step badges to guide users through the brand → landing → monitoring flow. Tile icons are replaced by
IntegrationIconsourced fromWELL_KNOWN_AGENT_TEMPLATES, and three new templates (brand-context,landing-page,system-health) are registered there.Screenshots/Demonstration
How to Test
bun run devand navigate to the home route.Migration Notes
No database migrations required. Old PNG assets under
public/home/are deleted; new SVGs replace them.Review Checklist
Summary by cubic
Redesigned the Home page with a server‑backed 3‑column tile board and a preset tasks system that auto‑pins tiles when started. Added onboarding agents and tools (brand context, system health, and web developer) with improved install flows and inline HTML previews.
New Features
/api/:org/home-board; tiles auto‑pin onPOST /preset-tasks/:id/start; icons useIntegrationIcon./preset-taskslists five cards (New chat, Extract brand context, Create landing page, Set up error monitoring, Import Deco);/startseeds a thread and returnstaskId; DBOS workflow tracks brand‑context completion; shared install dialogs and OAuth handshake for GitHub and System Health.brand-context: setup and confirm modes with built‑in tools (brand_context_setup,update_brand_context,reextract_brand_context,confirm_brand).system-health: idempotent install; new automation tools to create health checks (schedule/subscribe) and manage triggers.web-developer: built‑in tools (write_html_page,read_html_page,list_html_pages,delete_html_page); chat shows inline HTML previews.bg-card.Bug Fixes
Migration
public/home/replaced with SVGs.Written for commit b505e81. Summary will update on new commits.