Skip to main content
Glama

brand_generate_designmd

Synthesizes multi-page brand evidence into a single DESIGN.md design brief and design-synthesis.json with structured design tokens.

Instructions

Generate DESIGN.md (portable agent-facing design brief) and design-synthesis.json (structured radius, shadow, spacing, layout, motion, component, and personality signals) from the current brand system. Reads extraction-evidence.json when available for grounded visual signals; falls back to core-identity.yaml and tokens.json after manual edits. Use after brand_extract_site or brand_extract_visual to synthesize multi-page evidence into a single design brief. Use after brand_compile if evidence is unavailable. Returns file paths and synthesis source used. Read-only except for writing the two output files. NOT for extracting brand identity — use brand_extract_web or brand_extract_visual first.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sourceNoSource of truth for synthesis. Default prefers extraction evidence when available, otherwise current-brand.
overwriteNoIf false and DESIGN.md + design-synthesis.json already exist, return the existing artifacts without rewriting.

Implementation Reference

  • Main handler function for brand_generate_designmd. Creates a BrandDir instance, checks existence, then calls generateAndPersistDesignArtifacts to produce DESIGN.md and design-synthesis.json. Returns a structured response with file paths, synthesis source, and extracted design signals.
    async function handler(input: Params) {
      const brandDir = new BrandDir(process.cwd());
    
      if (!(await brandDir.exists())) {
        return buildResponse({
          what_happened: "No .brand/ directory found",
          next_steps: ["Run brand_start first to create the brand system"],
          data: { error: ERROR_CODES.NOT_INITIALIZED },
        });
      }
    
      const requestedEvidence = input.source === "evidence";
      const hasEvidence = await brandDir.hasExtractionEvidence();
    
      const result = await generateAndPersistDesignArtifacts(brandDir, {
        source: input.source,
        overwrite: input.overwrite,
      });
    
      return buildResponse({
        what_happened: input.overwrite === false && result.files_written.length === 0
          ? "Loaded existing design synthesis artifacts"
          : "Generated DESIGN.md and design-synthesis.json from the current brand state",
        next_steps: [
          "Use DESIGN.md as the portable agent-facing design brief",
          "Use design-synthesis.json when you need structured radius/shadow/layout/personality signals",
          ...(requestedEvidence && !hasEvidence ? ["Extraction evidence was not available, so the synthesis fell back to current-brand mode."] : []),
        ],
        data: {
          source_requested: input.source ?? "auto",
          source_used: result.source_used,
          files_written: result.files_written.length > 0 ? result.files_written : ["design-synthesis.json", "DESIGN.md"],
          design_synthesis_file: ".brand/design-synthesis.json",
          design_markdown_file: ".brand/DESIGN.md",
          evidence_summary: result.synthesis.evidence,
          personality: result.synthesis.personality,
          ambiguities: result.synthesis.ambiguities,
        },
      });
    }
  • Registration function that exports the tool as 'brand_generate_designmd' on the McpServer with params (source, overwrite), description, and a handler that validates via Zod schema then delegates to the main handler.
    export function register(server: McpServer) {
      server.tool(
        "brand_generate_designmd",
        "Generate DESIGN.md (portable agent-facing design brief) and design-synthesis.json (structured radius, shadow, spacing, layout, motion, component, and personality signals) from the current brand system. Reads extraction-evidence.json when available for grounded visual signals; falls back to core-identity.yaml and tokens.json after manual edits. Use after brand_extract_site or brand_extract_visual to synthesize multi-page evidence into a single design brief. Use after brand_compile if evidence is unavailable. Returns file paths and synthesis source used. Read-only except for writing the two output files. NOT for extracting brand identity — use brand_extract_web or brand_extract_visual first.",
        paramsShape,
        async (args) => {
          const parsed = ParamsSchema.safeParse(args);
          if (!parsed.success) {
            return buildResponse({
              what_happened: `Invalid parameters: ${parsed.error.message}`,
              next_steps: ["Check the source and overwrite parameters"],
              data: { error: parsed.error.format() },
            });
          }
          return handler(parsed.data);
        },
      );
    }
  • Zod schema for the tool's input: 'source' (enum: evidence|current-brand, optional) and 'overwrite' (boolean, default true). Also defines the Params type.
    const paramsShape = {
      source: z.enum(["evidence", "current-brand"]).optional()
        .describe("Source of truth for synthesis. Default prefers extraction evidence when available, otherwise current-brand."),
      overwrite: z.boolean().default(true)
        .describe("If false and DESIGN.md + design-synthesis.json already exist, return the existing artifacts without rewriting."),
    };
    
    const ParamsSchema = z.object(paramsShape);
    type Params = z.infer<typeof ParamsSchema>;
  • Core helper generateAndPersistDesignArtifacts that orchestrates the synthesis. Reads config, identity, evidence, tokens from BrandDir, calls buildDesignSynthesis and renderDesignMarkdown, then persists the results. Also handles the no-overwrite case by returning existing files.
    export async function generateAndPersistDesignArtifacts(
      brandDir: BrandDir,
      options: {
        source?: DesignSynthesisSource;
        overwrite?: boolean;
      } = {},
    ): Promise<PersistedDesignArtifacts> {
      const overwrite = options.overwrite ?? true;
    
      if (!overwrite && (await brandDir.hasDesignSynthesis()) && (await brandDir.hasDesignMarkdown())) {
        const synthesis = await brandDir.readDesignSynthesis<DesignSynthesisFile>();
        const markdown = await brandDir.readMarkdown("DESIGN.md");
        return {
          source_used: synthesis.source,
          synthesis,
          markdown,
          files_written: [],
        };
      }
    
      const config = await brandDir.readConfig();
      const identity = await brandDir.readCoreIdentity();
      const evidence = await brandDir.hasExtractionEvidence()
        ? await brandDir.readExtractionEvidence<ExtractionEvidenceFile>()
        : null;
      const tokens = await brandDir.hasTokens()
        ? await brandDir.readTokens()
        : null;
    
      const sourceUsed: DesignSynthesisSource = options.source ?? (evidence ? "evidence" : "current-brand");
      const synthesis = buildDesignSynthesis(config, identity, {
        evidence: sourceUsed === "evidence" ? evidence : null,
        tokens,
        source: sourceUsed,
      });
      const markdown = renderDesignMarkdown(synthesis);
    
      await brandDir.writeDesignSynthesis(synthesis);
      await brandDir.writeMarkdown("DESIGN.md", markdown);
    
      return {
        source_used: sourceUsed,
        synthesis,
        markdown,
        files_written: ["design-synthesis.json", "DESIGN.md"],
      };
    }
  • renderDesignMarkdown function that produces the DESIGN.md markdown document from the DesignSynthesisFile, covering visual theme, color palette, typography, component styling, layout, depth/elevation, motion, do/don't rules, and agent prompt guide.
    export function renderDesignMarkdown(synthesis: DesignSynthesisFile): string {
      const visualIntro = synthesis.source === "evidence"
        ? `This document is grounded in rendered site evidence across ${synthesis.evidence.pages_sampled} representative page(s) and ${synthesis.evidence.screenshots_analyzed} screenshot(s).`
        : "This document was synthesized from the current brand state because no deeper rendered evidence bundle was available.";
    
      return [
        "# DESIGN.md",
        "",
        `Brand: ${synthesis.brand.client_name}`,
        visualIntro,
        "",
        "## 1. Visual Theme and Atmosphere",
        "",
        `${synthesis.brand.client_name} reads as ${synthesis.personality.tone}. The palette skews ${synthesis.colors.mood.temperature} with ${synthesis.colors.mood.contrast} contrast, the corners feel ${synthesis.shape.corner_style}, and the overall elevation language is ${synthesis.depth.elevation_style}. Layout density is ${synthesis.layout.density}, which makes the system feel ${synthesis.personality.positioning}.`,
        "",
        "## 2. Color Palette and Roles",
        "",
        `Primary brand colors: ${synthesis.colors.brand.length > 0 ? synthesis.colors.brand.map((color) => `\`${color.role}\` ${color.value}`).join(", ") : "none confirmed"}.`,
        `Semantic support colors: ${synthesis.colors.semantic.length > 0 ? synthesis.colors.semantic.map((color) => `\`${color.role}\` ${color.value}`).join(", ") : "none confirmed"}.`,
        `Additional palette notes: ${synthesis.colors.additional.length > 0 ? synthesis.colors.additional.map((color) => `\`${color.name}\` ${color.value}`).join(", ") : "no additional token-worthy colors"}.`,
        "",
        "## 3. Typography Rules",
        "",
        `Font families: ${synthesis.typography.families.length > 0 ? synthesis.typography.families.map((family) => `${family.family} (${family.role}, ${family.character})`).join(", ") : "no strong typography signal detected"}.`,
        `Representative scale: ${synthesis.typography.scale.length > 0 ? synthesis.typography.scale.map((step) => `\`${step.selector}\` ${step.size}/${step.line_height ?? "auto"} weight ${step.weight}`).join(", ") : "no reliable scale extracted"}.`,
        "",
        "## 4. Component Styling",
        "",
        `Buttons: ${synthesis.components.button.count > 0 ? `dominant fill ${synthesis.components.button.dominant_fill ?? "none"}, text ${synthesis.components.button.dominant_text ?? "inherit"}, radius ${synthesis.components.button.dominant_radius ?? "none"}, shadow ${synthesis.components.button.dominant_shadow ?? "none"}.` : "No button instances were observed."}`,
        `Cards: ${synthesis.components.card.count > 0 ? `dominant fill ${synthesis.components.card.dominant_fill ?? "none"}, radius ${synthesis.components.card.dominant_radius ?? "none"}, shadow ${synthesis.components.card.dominant_shadow ?? "none"}.` : "No card pattern was observed."}`,
        `Inputs and nav: inputs use ${synthesis.components.input.dominant_radius ?? "unspecified"} radius; navigation fill resolves to ${synthesis.components.navigation.dominant_fill ?? "unspecified"}.`,
        `Button variants: ${synthesis.components.variants.buttons.length > 0 ? synthesis.components.variants.buttons.map((variant) => `${variant.variant} (${variant.backgroundColor ?? "transparent"}, radius ${variant.borderRadius ?? "0px"}, padding ${variant.padding ?? "auto"})`).join(", ") : "none detected"}.`,
        `Input variants: ${synthesis.components.variants.inputs.length > 0 ? synthesis.components.variants.inputs.map((variant) => variant.variant).join(", ") : "none detected"}. Badge variants: ${synthesis.components.variants.badges.length > 0 ? synthesis.components.variants.badges.map((variant) => variant.variant).join(", ") : "none detected"}.`,
        "",
        "## 5. Layout Principles",
        "",
        `Grid feel: ${synthesis.layout.grid_feel}.`,
        `Content width: ${synthesis.layout.content_width ?? "not confidently detected"}.`,
        `Spacing model: base unit ${synthesis.spacing.base_unit ?? "not confidently detected"} with detected scale ${synthesis.spacing.scale.length > 0 ? synthesis.spacing.scale.map((value) => `${value}px`).join(", ") : "unknown"}, common values ${synthesis.spacing.common_values.length > 0 ? synthesis.spacing.common_values.map((item) => `${item.px}px x${item.count}`).join(", ") : "unknown"}, component spacing ${synthesis.spacing.component_spacing.join(", ") || "unknown"}, and larger section spacing ${synthesis.spacing.section_spacing.join(", ") || "unknown"}.`,
        "",
        "## 6. Depth and Elevation",
        "",
        `Elevation style: ${synthesis.depth.elevation_style}.`,
        `Shadow scale: ${formatSignalList(synthesis.depth.shadow_scale)}.`,
        `Observed shadows: ${synthesis.depth.shadows.length > 0 ? synthesis.depth.shadows.map((shadow) => `${shadow.value} (${shadow.context}, x${shadow.count})`).join(", ") : "none detected"}.`,
        `Radius scale: ${formatSignalList(synthesis.shape.radius_scale)}.`,
        `Observed radii: ${synthesis.shape.values.length > 0 ? synthesis.shape.values.map((radius) => `${radius.value} x${radius.count}`).join(", ") : "none detected"}; dominant shape language is ${synthesis.shape.dominant_style}.`,
        "",
        "## 7. Motion and Interaction Tone",
        "",
        synthesis.motion.tone,
        `Observed duration tokens: ${formatSignalList(synthesis.motion.duration_tokens)}.`,
        `Observed easing tokens: ${formatSignalList(synthesis.motion.easing_tokens)}.`,
        "",
        "## 8. Do and Do Not Rules",
        "",
        ...buildDoRules(synthesis).map((rule) => `- Do: ${rule}`),
        ...buildDontRules(synthesis).map((rule) => `- Do not: ${rule}`),
        "",
        "## 9. Agent Prompt Guide",
        "",
        `- Describe the brand as ${synthesis.personality.tone}.`,
        `- Use ${synthesis.layout.grid_feel} layouts with ${synthesis.layout.density} spacing.`,
        `- Keep color emphasis centered on ${synthesis.colors.brand[0]?.value ?? "the confirmed primary brand color"} for actions and branded highlights.`,
        `- Preserve the ${synthesis.shape.corner_style} corner language and ${synthesis.depth.elevation_style} depth treatment.`,
        synthesis.ambiguities.length > 0 ? `- Ask for confirmation on these unresolved areas before high-stakes output: ${synthesis.ambiguities.join(" ")}` : "- The current synthesis is internally consistent enough to use as an agent-facing design brief.",
        "",
      ].join("\n");
    }
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It clearly states behavior: reads extraction-evidence.json, falls back to core-identity.yaml and tokens.json, is read-only except for writing two output files, and returns file paths and synthesis source. All behavioral traits disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single well-structured paragraph, front-loads purpose, then usage, then behavior. Every sentence adds value with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and lack of output schema, the description covers all necessary aspects: purpose, usage, behavior, parameters, and return values. It is complete for an agent to select and invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with descriptions for both parameters. The description adds context like 'Default prefers extraction evidence when available' for source and explains overwrite behavior, adding value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states it generates DESIGN.md and design-synthesis.json from the current brand system, using specific verbs and resources. It also distinguishes from sibling tools by stating 'NOT for extracting brand identity — use brand_extract_web or brand_extract_visual first.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use guidance: 'Use after brand_extract_site or brand_extract_visual... Use after brand_compile if evidence is unavailable.' Also gives clear exclusions and alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Brandcode-Studio/brandsystem-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server