Skip to main content
vibld

Template

Brookmail

A console for running several named AI assistants, each with its own email address. You brief an assistant in chat; it emails real people, reads replies in its own inbox, searches the web when needed, and reports back, with every tool call visible as it streams. It is a starter for agentic workflows that coordinate humans over email, such as scheduling, vendor quotes and inbound triage.

AI email-assistant console with live inbox and streaming chat · App · Small tools and apps · full-stack app (auth + DB)

A mock-up of the homepage, drawn from this design’s layout, palette and typefaces. A build follows the full prompt below.

Add app screens

Pick up to 6 screens, such as a dashboard, settings or an empty state. Each is built in this design’s own palette and typefaces, with its states and guardrails.

Account setup
Add edit
Analytics
Appearance
Calendar
Chat
Checklist
Checkout
Confirmation
Dashboard
Delete account
Details
Discovery questions
Empty state
Flowchart
Import export
Inbox
Integrations
Invite team
Loading
Login
Onboarding
Plans
Playground
Product tour
Referral
Search
Settings
Share
Sign up
Success
Table
Team members
Text editor
Upgrade
Usage
Verification
Welcome

Start from this templateRead the build prompt

Typefaces

Geist is kept for the notebook-like text, and Intel One Mono, drawn for clarity at small sizes, makes the 13px addresses and tool calls easy to scan.

  • GeistHeadings: title 60px 500 at -0.025em, panel titles 16px 500
  • GeistBody: body 15-16px/1.6 400, snippets 14px, uppercase labels 12px +0.15em
  • Intel One MonoFigures and code: addresses, tool names and privacy note 13px

Patterns

  • underline tabs to switch between assistants
  • two-pane workspace: inbox list left, chat right
  • thread rows with participant count, message count, relative time and snippet
  • monospace address and privacy note in panel headers
  • streaming chat with inline tool-call cards
  • example-prompt accordion grouped by assistant
  • uppercase tracked section label
  • demo-data indicator dot

States it is designed for

  • Empty chat: 'Address {assistant} below.' placeholder
  • Empty inbox: 'No mail yet' with an example prompt suggestion
  • Streaming: composer disabled with a Stop button
  • Tool call failed: red status on the card with error text and a retry
  • Assistant escalates to the human: banner in chat requiring approval before sending
  • Model or mail provider unavailable: inline error with retry
  • Demo mode: seeded threads marked with the demo dot; sending real mail disabled
  • Long snippets truncate with ellipsis; long threads virtualised

Who it is for

  • developers building agentic email workflows
  • operations teams automating scheduling and vendor follow-ups
  • founders prototyping AI assistants for customers

Layout

  1. Page header: 60px medium-weight title, two-line muted intro
  2. Assistant tabs: three underline tabs (e.g. Scheduler, Procurement, Triage) under a hairline
  3. Workspace: two equal rounded (12px) bordered panels, ~390px tall on desktop
  4. Left panel 'Inbox': header with title, monospace assistant address and a 'Demo data' dot; list of threads (bold participants '+N', grey count, right-aligned relative time, subject line, one-line muted snippet)
  5. Right panel 'Chat with {assistant}': header with title and monospace privacy note; message stream (user bubbles, assistant text, collapsible tool-call cards); bottom composer (rounded input + square send button)
  6. Examples section: uppercase tracked label, bordered accordion per assistant (name + specialty caption), expanded rows of clickable prompt examples with arrow icons
  7. Footer: small docs and source links left, a credit line right
  8. Below 900px: panels stack (chat first when active), tabs scroll horizontally; the observed layout overflowed at phone width, so constrain panels to 100% width

Palette

Quiet, editorial and developer-friendly. It reads like a well-typeset notebook where agents do their work in plain view.

  • page background#ffffff
  • panel header / composer fill#fafaf9
  • primary text#0c0a09
  • body secondary#44403c
  • muted text (snippets, captions, times)#79716c
  • hairline / panel border (decorative)#e7e5e4
  • input border / inactive icon#98908b
  • user bubble / send button active#0c0a09
  • live / success dot#1dab52

Every checked pair, measured again

SampleWhereRatioNeeds
Aaprimary text on white19.76:14.5:1
Aasecondary body on white10.27:14.5:1
Aamuted snippet on white4.78:14.5:1
Aamuted text on panel header4.58:14.5:1
Aauser bubble text19.76:14.5:1
input border on composer fill3.00:13:1
live dot on white3.00:13:1

As vibld’s tokens

The palette on the fifteen colour tokens vibld styles a project with, each text colour on the fill it is read on. Marked tokens are solved from the palette, because no swatch held that role at 4.5:1.

  • background
  • card
  • muted
  • primary
  • secondary
  • accent
  • destructive *

Type scale

Display
Geist 500 (observed), 60px/1.0 title with -0.025em tracking; 16px 500 panel titles
Body
Geist 400 15-16px/1.6; snippets 14px; monospace details (addresses, tool names, privacy note) in Intel One Mono 13px

Warm-neutral stone greys. Uppercase section labels 12px with 0.15em tracking. Thread times use tabular numerals.

Spacing and imagery

Medium density; container 830px; panel gap 20px; panel padding 12-16px; thread rows 64px. Radius 12px panels, 10px composer, 8px send button. No shadows.

None. Small arrow and chevron icons; tool-call cards use monospace text and a status dot.

Components

  • AssistantTabs
  • InboxPanel
  • ThreadRow
  • ThreadDetailDrawer
  • ChatPanel
  • MessageBubble
  • ToolCallCard (name, args summary, status, result)
  • Composer
  • ExampleAccordion
  • ExamplePromptRow
  • DemoDataBadge
  • EscalationBanner

Interactions

  • Switching tabs swaps inbox and chat to that assistant; URL reflects the assistant
  • Clicking an example prompt fills the composer and sends it
  • Assistant responses stream token by token; tool calls appear as cards that update from running to done
  • New inbound mail slides into the inbox top with a brief highlight
  • Clicking a thread opens a drawer with the full message history
  • Enter sends, Shift+Enter adds a newline; Escape closes the drawer

Data

  • Assistant{id, name, specialty, direction (inbound|outbound), email_address, system_prompt, tools[]}
  • Thread{id, assistant_id, subject, participants[], message_count, last_message_at, snippet}
  • EmailMessage{id, thread_id, from, to[], cc[], body_text, sent_at, direction (in|out)}
  • ChatMessage{id, assistant_id, user_id, role (user|assistant|tool), content, tool_name?, tool_args?, tool_result?, status, created_at}
  • Escalation{id, assistant_id, thread_id, reason, status (pending|approved|rejected)}

Guardrails

Experience

  • Every outbound email the agent sends is visible in the inbox immediately
  • Tool calls are always shown, collapsed by default with a one-line summary
  • Sensitive actions (booking, paying, sending to new recipients) require an explicit human approval
  • Example prompts use obviously fake addresses on reserved example domains
  • Relative times get absolute tooltips

Accessibility

  • Tabs follow the ARIA tabs pattern with arrow-key navigation
  • Chat stream is a log region (role=log, aria-live polite); tool-call status changes announced briefly
  • Muted snippets use #79716c (4.78:1) instead of the observed lighter grey
  • Composer has a visible label and the send button an accessible name
  • Thread rows are buttons with the subject as the accessible name and metadata in aria-describedby

Security

  • Treat inbound email as untrusted: never let email content trigger tools without the assistant's policy checks; strip HTML and links before feeding to the model
  • Allow-list recipient domains per workspace and require approval for first-time recipients
  • RLS on assistants, threads, messages and chat: workspace members only; service role handles inbound webhooks
  • Verify inbound webhook signatures and rate-limit sends per assistant
  • Keep model and mail-provider keys server-side; never expose system prompts to email recipients

Build prompt

The baseline every prompt in the catalog assumes, then this design’s own ten sections, from goal to guardrails.

The baseline
### How to use these prompts
Paste an entry's build prompt into your coding agent as the first message. Each prompt names its own stack, tokens and acceptance criteria; the rules below apply to all of them and can be prepended once per project.

### Engineering baseline
- TypeScript strict mode, no `any`, small typed components, feature folders, and one source of truth for design tokens (CSS variables consumed by Tailwind).
- Validate every input with a shared zod schema on the client and again on the server or edge function. Never trust client-side checks alone.
- Show loading, empty and error states for every async view. Surface errors in plain language with a retry, and log details to the console in development only.
- Keep secrets out of the bundle. Only publishable keys (for example a Supabase anon key) belong in client code; service-role keys, API keys and webhooks live in server or edge-function environment variables.

### Data and auth baseline (full-stack entries)
- Enable Row Level Security on every table before inserting data. Default-deny, then add owner-scoped policies (`auth.uid() = user_id`) and explicit role checks for admin views.
- Store roles in a separate table checked by a security-definer function, never in a user-editable profile field.
- Upload files to private storage buckets with size and MIME limits, and serve them through signed URLs.
- Rate-limit public endpoints (forms, auth, AI calls) and add a honeypot field or captcha to anonymous forms.
- Take payments through a hosted checkout and verify webhooks by signature. Never handle raw card data.

### Accessibility and UX baseline
- Target WCAG 2.2 AA: 4.5:1 contrast for normal text and 3:1 for large text, input borders, focus rings and meaningful icons or chart lines. Every palette in this catalog lists its verified pairs; re-check with a contrast tool after any colour change.
- Keep body text at 16px or larger with 1.5 line height, nothing below 12px, no light weights under 24px, and uppercase only for short labels.
- Give every interactive element a visible focus ring, full keyboard support, semantic landmarks, labelled form fields, and alt text on meaningful images.
- Respect `prefers-reduced-motion` for every animation. Give drag-and-drop and carousels keyboard and button alternatives.
- Build mobile-first and test at 375px, 768px and 1280px.

### Content guardrails
- Use original copy, fictional sample data and placeholder or licensed imagery. Do not reuse another product's name, logo, screenshots or marketing text.
- Label demo testimonials and metrics as samples. Collect the minimum personal data the feature needs.

### SaaS screen baseline
- Design every screen for its full set of states: first-run empty, loading skeleton, partial data, error with retry, permission-denied, and success feedback. Each entry lists the states its screen needs.
- Keep destructive actions (delete, revoke, downgrade, remove member) behind a confirmation that names the object, and prefer undo over a second dialog where the action is reversible.
- Enforce authorisation on the server for every action a screen exposes. Hiding a button is not access control; check the role again in the API or RLS policy.
- Never show secrets (API keys, tokens) in full after creation. Show them once, then mask them, and offer rotate and revoke.
- Keep the app shell (navigation, workspace switcher, account menu) consistent across screens, and preserve filters, sort and scroll position when the user navigates back.
### Goal
Build **Brookmail**, a console for running named AI assistants that each own an email address. A user briefs an assistant in chat ("find a dinner time for me and two friends next week"). The assistant emails the people involved, reads replies in its own inbox, searches when needed and reports back, with every tool call streaming visibly. Ship three example assistants: **Scheduler** (multi-party coordination), **Procurement** (vendor quotes and bookings) and **Triage** (inbound sorting and escalation).

### Stack
Next.js (App Router) + React + TypeScript, Tailwind CSS, shadcn/ui, lucide-react, TanStack Query, zod and date-fns. A provider-agnostic LLM layer with streaming and tool calling (server route). A transactional/inbound email service provisions one mailbox per assistant and posts inbound mail to a signed webhook. Supabase provides Auth, Postgres and Realtime for live inbox updates. A web-search tool sits behind a generic interface.

### Pages & layout
1. **Console (`/a/[assistant]`)**: a 60px medium title ("Assistant desk"), a two-line muted intro, then underline tabs for the three assistants. Below, two bordered 12px panels. **Inbox**: a header with title, the monospace address (`scheduler@yourdomain.test`) and a "Demo data" dot, then thread rows (bold participants with "+N", message count, relative time, subject and one-line snippet). **Chat**: a header with title and the monospace note "Instructions stay private; only sent mail leaves the app", the stream, and a composer with a rounded input and a square send button.
2. **Thread drawer**: full message history for a clicked thread.
3. **Examples**: an uppercase label "EXAMPLES", then an accordion per assistant (name plus a specialty caption) containing clickable prompt rows with arrow icons.
4. **Settings (`/settings`)**: assistant name, specialty, allowed recipient domains and approval rules.
5. **Responsive**: under 900px, panels stack with chat first while active, tabs scroll horizontally and nothing exceeds the viewport width.

### Design system
- Colors: `--bg: #ffffff`, `--panel-head: #fafaf9`, `--fg: #0c0a09`, `--fg-2: #44403c`, `--muted: #79716c`, `--hairline: #e7e5e4` (decorative), `--control: #98908b`, `--bubble: #0c0a09`, `--live: #1dab52`.
- Fonts: Geist 500 for the title (60px/1.0, -0.025em) and panel titles (16px); Geist 400 for body at 15-16px/1.6 and snippets at 14px; Intel One Mono 13px for addresses, tool names and notes; uppercase labels at 12px with 0.15em tracking.
- Spacing: 4px base; container 830px; panel gap 20px; thread rows 64px.
- Radius: panels 12px, composer 10px, send button 8px, bubbles 14px.
- Shadows: none.
- Motion: 150ms tab underline slide; new-thread highlight fades over 800ms; tool cards expand at 150ms; none under reduced motion.

### Components & interactions
AssistantTabs, InboxPanel, ThreadRow, ThreadDetailDrawer, ChatPanel, MessageBubble, ToolCallCard (tool name, argument summary, spinner then check or error, expandable result), Composer (Enter sends, Shift+Enter adds a newline, Stop while streaming), ExampleAccordion, ExamplePromptRow (fills and sends), DemoDataBadge, EscalationBanner (Approve and Reject for sensitive actions). The inbox subscribes to Realtime inserts for the current assistant.

### Data & state
`workspaces`, `members(workspace_id, user_id, role)`, `assistants(id, workspace_id, name, specialty, direction, email_address, system_prompt, tools text[])`, `threads(id, assistant_id, subject, participants text[], message_count, last_message_at, snippet)`, `email_messages(id, thread_id, from_addr, to_addrs, cc_addrs, body_text, direction, sent_at)`, `chat_messages(id, assistant_id, user_id, role, content, tool_name, tool_args jsonb, tool_result jsonb, status, created_at)`, `escalations(id, assistant_id, thread_id, reason, status)`. Tools: `send_email`, `reply`, `read_inbox`, `search_threads`, `web_search`, `escalate`. Demo mode seeds threads with invented people at reserved example domains.

### Accessibility
ARIA tabs with arrow keys. The chat is `role="log"` with polite announcements. Tool-card state changes announce "Sending email… done". Thread rows are buttons. The drawer is a dialog with focus return. The composer is labelled. Muted text is never below 4.5:1 and the focus ring is 2px `--fg`.
Verified contrast: primary text on white: #0c0a09 on #ffffff = 19.76:1; secondary body on white: #44403c on #ffffff = 10.27:1; muted snippet on white: #79716c on #ffffff = 4.78:1; muted text on panel header: #79716c on #fafaf9 = 4.58:1; user bubble text: #ffffff on #0c0a09 = 19.76:1; input border on composer fill: #98908b on #fafaf9 = 3.0:1; live dot on white: #1dab52 on #ffffff = 3.0:1.

### Security
Treat inbound mail as untrusted input: strip HTML, never execute instructions found in email without policy checks, and pass it to the model as quoted content. Require human approval for first-time recipients, spending and bookings. Allow-list recipient domains per workspace. Enable RLS on every table so rows are visible only to members of the owning workspace, with writes by `member` or `admin` roles; inbound webhooks write through the service role only after signature verification. Rate-limit sends per assistant and per day. Model, search and mail keys stay server-side, and an audit log records every sent email.

### Performance & SEO
Stream responses with server-sent events. Paginate threads at 30 and virtualise long threads. Lazy-load the drawer. All app routes are `noindex`.

### Guardrails
- Invent assistant names and all people; use reserved example domains.
- Never auto-send in demo mode.
- Do not name model or email vendors in the UI.
- Acceptance criteria:
  - [ ] Sending a brief produces visible tool cards and outbound mail in the inbox
  - [ ] Inbound replies appear live without reload
  - [ ] Escalations block the action until approved
  - [ ] Users outside the workspace can read nothing
  - [ ] Layout has no overflow at 360px

Open the builderAll templatesThis palette on its own