Brand Bot — Product Extensions
Status: Living doc — first written 2026-05-01
Author: Eric Downs (Technical Director, Grain & Mortar)
Sibling docs: PRD.md (platform) · README.md (timeline)
What this doc is
PRD.md describes the platform — the multi-tenant MCP server, the surfaces (Slack, Claude Code skill, Codex, design-tool skill, direct), the per-tenant subscription model, the pricing, the auth + cost-attribution plumbing.
This doc describes the product line that rides on the platform — Brand Check, Design Check, Strategy Bot, the deferred generative tools, and anything else future Claude sessions should know is in the pipeline. Treat it as the catalog of what Brand Bot can do for a client, separately roadmapped from what Brand Bot is built on.
The line stays clean if every extension is described in two places only: 1. A short section here — tagline, status, MCP tools, surfaces, next step, links. 2. Wherever the detailed spec lives — discovery card, scoping doc, PRD section if it touches the platform.
This doc does NOT duplicate platform-level facts (architecture, billing, infra). If you find yourself restating PRD content, cross-link instead.
Mental model: surface-agnostic engine, thin per-surface adapters
Every extension is built the same way on purpose:
- Engine — pure server-side function. Takes a tenant's brand-guide JSON (from the MCP) plus the input the extension is checking or generating against. Returns structured JSON. Deterministic where possible; LLM-augmented only where deterministic falls short.
- MCP tool wrapper — registers the engine as a tool on the brand-guide MCP so any MCP-aware caller (Claude Code, Codex, custom agent) can hit it.
- Per-surface adapters — Slack modal / portal page / Telegram reply / SMS summary / raw API. Adapters render the engine's structured JSON; they don't re-implement logic.
lib/brand-check/{rules,engine}.ts is the existing reference implementation. Brand Check is a pure-rule engine over text input; Design Check is the same pattern with image input + vision + OCR; Strategy Bot is the same pattern with a private strategy doc as the corpus instead of a brand guide. New extensions inherit the pattern.
Why the discipline matters: it's how we keep the per-tenant surface toggling working ("client doesn't use Slack → still gets the product via portal/Claude Code/etc.") and how we onboard new surfaces (Telegram, SMS, browser portal) without rewriting the product logic.
Extensions
Brand Check — text-input compliance check
Tagline: Paste copy, get a deterministic pass/fail against the tenant's voice + naming rules.
Status: Live. Shipped 2026-04-22 (engine), 2026-04-27 (Slack message-shortcut), 2026-05-04 (check_text MCP tool + Banned Terms rule), 2026-05-05 (Numbers rule no longer false-positives on measurements; shareable result links at /brand-check/r/[uuid] with dynamic next/og Slack-unfurl card showing the verdict — junior-designer-to-creative-director sign-off ramp).
MCP tools consumed: get_voice, get_messaging. Engine is also exposed as the check_text MCP tool for external surfaces (added 2026-05-04 during Guardify onboarding).
Surfaces:
- Slack message shortcut ("Check brand guide" — right-click any message → modal with per-rule ✓/✗ + summary)
- Slack /brand check <text> slash subcommand (paste-modal path)
- Web GUI on tenant-branded sites via the check_text MCP tool — first consumer is guardify-brand-bot.vercel.app/brand-check (live)
How it works: Five deterministic rules over the tenant's brand-guide JSON — naming (banned aliases from messaging.namingConventions with usage: "never"), banned terms (literal phrases from messaging.bannedTerms), contractions (when voice.writingRules says "use them"), numbers (when voice.writingRules says spell out one through nine; measurement-shaped tokens like hex codes / RGB / CMYK / Pantone / ΔE / % / CSS units / dates / versions / scores / ratios / dimensions are masked first so they don't false-positive), jargon (3–5 word fingerprints from voice.examples[].bad, fuzzy-matched). Pure functions, content-driven, skipped silently if source content is missing. Engine: lib/brand-check/{rules,engine}.ts.
Next step: LLM tone-augmentation layer (the gating step before generative tools — see Voice Writer / Compliance Check below). Audience-aware checking (Prosecution / Child Advocacy / Law Enforcement variants visible in Guardify's voice.json) is also called out on /brand-check's footer as roadmap.
Chat / Q&A — multi-turn web chat over the brand guide
Tagline: "What's our hex for True Blue?" / "Is this headline on-brand for the prosecution audience?" — a real conversational interface to the brand guide, scoped to one tenant per deploy.
Status: Live (shipped 2026-05-05 as the fourth and final customer-facing surface). First consumer is guardify-brand-bot.vercel.app/chat.
MCP tools consumed: All read tools (get_*, search). The agent picks based on the question.
Architecture:
- Backend: lib/chat-agent.ts is a surface-agnostic agent loop, parallel to (not shared with) the Slack agent in lib/agent.ts. The Slack loop is too Slack-coupled to reuse — it does thread-history fetch, mrkdwn formatting, and Slack-user-keyed memory. The chat agent skips all three: caller passes multi-turn history in the request body, system prompt asks for standard CommonMark, no memory tool (anonymous web visitors don't have stable identity to scope memory against — revisit when sign-in lands).
- Endpoint: app/api/agent/[tenantId]/route.ts accepts {messages: [{role, content}]}, runs the agent, returns {text, responseId, stopReason}. Same auth + subscription + rate-limit pattern as /api/mcp and /api/design-check — MCP_SHARED_SECRET (slack/internal bypass) OR per-tenant API key with surface=chat. New chat value in EXTERNAL_SURFACES.
- Per-tenant frontend: server-side proxy holds the API key in env so it never reaches the browser. Reference impl: guardify-brand-bot/app/api/agent-proxy/route.ts + app/chat/chat-interface.tsx (ReactMarkdown rendering, suggestion chips, Send-on-Enter, ARIA live region).
Surfaces: Web GUI on tenant-branded sites. Could also expose to Claude Code / Codex via raw API key, but the Slack agent already covers MCP-aware callers.
Cost shape: Pure Anthropic Messages API call with the brand-guide MCP attached. Spend lands on the tenant via the standard recordedMessagesCreate choke point. No per-call accumulator beyond what /admin/usage already shows.
Why no memory yet: anonymous visitors → no stable user id → can't scope a memory tool safely. When portal sign-in or per-session JWTs land, the memory tool can layer in the same way it does for Slack — same PostgresMemoryStore shape.
Onboarding a new tenant to chat:
1. /admin/api-keys → issue surface=chat key
2. Save to 1Password, drop into the tenant's frontend Vercel project as <TENANT>_CHAT_API_KEY
3. Tenant's frontend implements an /api/agent-proxy route forwarding to /api/agent/<tenant-id> with the key
Next step: Watch first-week usage on Guardify (passive). Decide whether memory + sign-in is worth shipping on the back of real visitor traffic patterns.
Brand Insights — what your team is asking, what your guide is missing
Tagline: Every question your team asks the bot is a signal. We surface them as a research report on your brand guide's quality, with concrete recommendations for what to add next.
Status: MVP shipped 2026-05-05 (G&M-internal admin view). Tenant-facing portal view + weekly email digest + LLM-generated update suggestions are queued as phases 4-7 of the same build sequence.
Why this is a product feature, not just analytics: every chat/search tool that succeeds long-term has an analytics layer aimed at the content owner. Intercom Fin, Zendesk Answer Bot, Algolia (zero-result-queries report), Mintlify — all do exactly this. The pattern is consistent: surface to the content owner, frame as "you should add content for this," that's where the stickiness lives. Brand Bot follows the same playbook with brand guides as the source-of-truth corpus.
MCP tools consumed: none directly — derives signals from the chat agent's tool-call traces. Free classifier: when the agent calls get_colors, the question was about colors.
Architecture:
- Capture (lib/insights/capture.ts, called by lib/chat-agent.ts after each turn) — extracts the MCP tool names from response.content, maps them to a single category enum (colors, voice, messaging, logos, icons, photography, brand_foundation, applications, typography, brand_check, search, multi, unknown). Regex scans the response text for the system-prompt's "doesn't specify" hedge phrases. Writes one chat_insights row.
- Schema (chat_insights table) — narrow on purpose. tenant_id, surface, category, hedged, created_at, request_id (FK soft join to usage_events for cost). NO raw question/response text. Privacy promise on the chat surface ("we don't persist your messages") stays intact.
- Aggregate (lib/insights/queries.ts) — topCategories, dailyVolume, summariesPerTenant, all per-tenant + time-windowed.
- Surfaces: /admin/insights (G&M-internal, shipped). Future: /portal/[tenantId]/insights (tenant-facing), weekly email digest via Vercel cron + Brevo, LLM-generated "suggested brand-guide updates" from clustered hedged questions.
The killer feature (phase 7, not built yet): weekly digest email to the brand owner that says "your team asked 47 questions. The bot couldn't fully answer 5 of them, all about photography. Here are the three specific gaps in your photography section, with suggested paragraphs to add." That's the report that makes the bot a brand intelligence tool, not a chat log — and the cancellation conversation impossible.
Privacy posture caveat: for phase 7 we'll need to either (a) cluster the hedged questions via an LLM pass that sees the raw question text in-flight but doesn't persist it, or (b) opt-in per-tenant for raw text storage. The MVP doesn't make that decision — it just establishes the foundation.
Cards:
- Build sequence: phase-numbered in docs/ROADMAP.md "Recently shipped" + the not-yet-shipped phases below.
- Future phases (4-7) to file when ready: tenant-facing portal view, weekly email digest, LLM-generated update suggestions.
Next step: let real traffic accumulate (1-2 weeks of organic Guardify usage) before building phase 4. The MVP report needs enough rows to look meaningful before we put it in front of a client.
Design Check / Brand Guardrails — image-input compliance check
Tagline: Drop in a designed asset (Instagram ad, social tile, pitch slide), get a structured brand-compliance score across colors, typography, voice (on visible text), and overall brand fit.
Status: In flight — Phase 0 spike scoped against the G&M tenant, discovery for the first paying client also open.
MCP tools consumed: get_colors, get_voice, get_messaging, get_brand_foundation (system-prompt context for the vision model).
Planned MCP tool: check_design(image, options) → DesignCheckResult once the spike validates output quality.
Surfaces (planned): Slack message shortcut on a message-with-image, customer portal upload page, raw API for design-tool skill drag-drop.
Architecture: Sharp dominant-color extraction + Delta E vs the tenant palette, Anthropic Sonnet vision OCR (with Tesseract fallback if needed), Claude Sonnet vision call with brand context in the system prompt for 5-dimension scoring, OCR'd text fed back through runBrandCheck so the existing voice rules apply unchanged. Phase 0 spike is throwaway; Phase 1 rewrites once the architecture is validated.
Open questions: - File types beyond JPG/PNG (Figma exports? PDF? video frames?) - Output mode — pass/fail score vs annotated suggestions with bounding boxes - Strictness — pixel-perfect or directional - Whether typography detection (the hardest, lowest-accuracy part) is in scope for v1
Cards:
- Discovery (client TBD): 6gWJ32QRVqjRh727
- Phase 0 spike (G&M tenant): 6gWJ4qJ25j28vF6f
- Scope doc: ~/Desktop/brand-bot-design-check-scope.md
- Background research: ~/Desktop/brand-bot-design-qa-research.md
Next step: Run the Phase 0 spike against G&M ad PNGs; document accuracy + token cost in DESIGN-CHECK-SPIKE-FINDINGS.md; use those findings to scope Phase 1 for the first paying client.
Strategy Bot — private-doc business-strategy chat
Tagline: Pose a business decision, get a check against the company's strategy guide.
Status: Discovery — client TBD, scoping pending.
MCP tools consumed (proposed): New tool family — get_strategy, search_strategy(query) — over the same MCP, mirroring get_voice / search for brand content. Could share the existing brand-guide MCP server (extra tool family, per-tenant flag) or stand up a sibling strategy-mcp if the schemas diverge enough.
Surfaces (planned): Slack /strategy ask <q> slash command; @mention path same shape as Brand Bot's agent loop; portal Q&A view; raw API for custom agentic workflows.
Architecture (proposed): Same MCP-as-product pattern. Strategy guide ingestion (PDF/Doc/Notion → structured JSON, same as how brand-guide content is shaped), retrieval over that corpus, agent loop with the strategy-tools attached. Likely 80% code reuse from Brand Bot if we keep the schemas parallel.
Three packaging paths, undecided: 1. Brand Bot variant rebranded ("Strategy Bot" sibling product) — separate sale, separate MCP, full reuse of the platform. 2. Brand Bot extension that ingests non-brand docs — same MCP, expanded tool surface. 3. Standalone product — separate retainer, separate Slack app, separate everything.
The packaging decision drives the MCP boundary, which drives the engineering. Locked once we have a real client + a real strategy doc to scope against.
Card: Discovery: 6gWJ2wjmG9FgPQRf
Next step: Get a copy of a real client's strategy guide so we can size the corpus + decide on packaging path. Competitive scan against Custom GPTs, Claude Projects, NotebookLM, Glean, OpenAI Assistants is open work in the discovery card.
Voice Writer — generate on-brand copy
Tagline: "Draft a tagline for our spring campaign in our voice" → on-brand copy from the brand guide's voice + messaging pillars.
Status: Deferred. Tracked in PRD.md Section 8 as Phase 1 generative tool write_in_voice. Not actively in flight.
MCP tool (planned): write_in_voice(brief, constraints) → string
Surfaces (planned): Slack agent loop (@mention / DM), Claude Code skill, Codex.
Why deferred: Brand Check graduated from rule-engine-only is the gating step. Until the deterministic compliance pass is solid, generative output has no automated quality gate — and shipping a writer with no checker creates "AI slop" risk that pushes the bot out of "premium brand agent" territory and into "chat log."
Next step: Revisit when (a) Brand Check has graduated past pure rule-engine into LLM-augmented tone scoring, OR (b) a paying client requests it explicitly. Whichever comes first.
Compliance Check — LLM-augmented brand-fit assessment
Tagline: "Is this copy on-brand?" → rule violations (deterministic, from Brand Check) + tone assessment (LLM, against voice.toneAttributes + voice.examples).
Status: Deferred. Tracked in PRD.md Section 8 as Phase 1 generative tool check_compliance.
MCP tool (planned): check_compliance(copy) → { ruleResults, toneAssessment, suggestions }
Relationship to Brand Check: This is Brand Check + an LLM tone layer. Brand Check today returns deterministic rule pass/fail. Compliance Check adds: a Claude Sonnet pass over the copy with the brand's voice in the system prompt, returning a structured tone score across the brand's toneAttributes plus suggested rewrites for failed rules.
Surfaces (planned): Same surface set as Brand Check, with the LLM tone block rendered alongside the rule rows.
Why deferred: Same reason as Voice Writer — rule engine is shipping value today and the LLM augmentation needs scoping (which model, which prompt format, what's the cost shape per call).
Next step: Spike against G&M tenant copy once Voice Writer or Design Check has produced LLM-augmentation cost data we can extrapolate from.
Future possibilities
Captured here so they're not lost; not on any roadmap unless promoted to their own section above.
- Asset Delivery — Slack file upload of the right logo/asset variant for the requesting context (channel topic, slash arg). Mentioned in the original 2026-04-21 PRD but not scoped beyond.
- Localization / multi-language brand guides — same brand guide schema in multiple locales. Listed in PRD Phase 3+.
- Per-workspace custom branding — beyond the existing
chat:write.customizeper-tenant identity, full brand kit (color theme on App Home, custom slash command names) per workspace. PRD Phase 3+. - Resellable white-label MCP — let agencies stand up their own Brand Bot under their own bot identity. PRD Phase 3+.
- Telegram / SMS / Discord / Teams adapters — additional surfaces over the existing engine. The engine doesn't change; new adapters slot in next to Slack.
- Photography mood-match (image → "fits the photography rules?") — a Design Check sibling specifically for photography assets, scoring against
photography.json(composition, subject matter, art direction). - Token / spec emitter — generate a Figma variable JSON or CSS token file from the brand guide on demand, for engineering teams setting up a new project.
- Pull-from-Figma onboarding tool —
pull-from-figma <fileKey>script (CLI or admin UI) that reads a tenant's Figma file via the Figma API and seedscontent/colors.json/content/typography.json/ partialcontent/logos.jsonfrom variables + components. The 2026-05-05 Guardify ask to Nicholas leads with "share the Figma file" precisely because this is how the next ten tenants should onboard. Manual JSON authoring is fine for two tenants; doesn't scale. - Live-linked Figma source-of-truth — extension of the above where the brand-guide MCP polls the source Figma file periodically and surfaces drift between what the MCP serves and what's currently in Figma. Designer changes a hex → MCP shows a diff in
/admin→ admin one-click accepts the update. Nicholas-style external designers stay productive in their tool of choice; we stay the source of truth that surfaces consume.
Cross-references
- Platform PRD:
PRD.md(sections 2 + 4.5 + 8 + 14 + 16 are most relevant to extensions) - Repo CLAUDE.md:
~/Projects/brand-guide-mcp/CLAUDE.md - Repo ROADMAP (deferred items at platform level):
docs/ROADMAP.md - Existing brand-check engine:
lib/brand-check/{rules,engine}.ts - MCP tool registry pattern:
lib/mcp/tools.ts - Brand Bot Todoist project:
Brand Bot 🎨