envious-canvas v2 API Contract
Defines a six-tool API contract for AI-powered marketing asset creation, planning, editing, and layout rendering.
What this file does
Defines a six-tool API contract for AI-powered marketing asset creation, planning, editing, and layout rendering.
When to use it
- Building an AI agent that generates marketing images from creative briefs
- Designing a tool-based API for brand asset management and image editing
- Implementing a planning step before generative image calls
- Creating a system that renders HTML/CSS layouts to pixel images
Assumes this stack
envious-canvas v2 API Contract
North star: Every creative request starts as a Creative Brief interview, not a render call.
1. Plan Object Schema (the backbone)
The plan object is the central artifact. All generation flows through it. Prompts shape workflow, but execution gating happens server-side via approved plan validation.
class CreativePlan(BaseModel):
"""A validated, approved plan for asset creation."""
plan_id: str # Unique ID (plan_<uuid>)
status: Literal["draft", "approved", "executing", "completed", "expired", "failed"]
created_at: str # ISO 8601
expires_at: str # Plan expires after 1 hour
# Intent
normalized_intent: str # Server-normalized version of user's goal
subject_type: Literal["product", "logo", "person", "pet", "object", "scene"] | None
target_channels: list[str] # ["ig_feed_square", "ig_stories"]
variant_count: int # 1-5
# Assets & References
product_image: str | None # Path to reference product photo
brand_kit_id: str | None # Brand kit identifier
style_image: str | None # Style reference (or auto from brand kit)
# Fidelity
fidelity_mode: Literal["creative", "fidelity_assisted", "fidelity_strict", "composite_lock"]
identity_lock: Literal["none", "medium", "hard"]
allowed_changes: list[str] # ["background", "lighting", "camera_angle", "styling"]
forbidden_changes: list[str] # ["shape", "proportions", "hardware", "colorway"]
# Creative Direction
prompt: str # The generation prompt (may be refined during intake)
negative_prompt: str
color_grading: str | None # Preset name or None
logo_overlay: bool
# Execution Plan
workflow: Literal["creative_generation", "conditioned_edit", "composite_lock", "html_layout"]
provider_model: str | None # "openai/gpt-image-1" or "replicate/flux-kontext-pro"
tuning: dict[str, Any] # Validated tuning params
# Output
output_specs: list[dict] # [{channel, width, height, format}]
estimated_cost: dict | None # {per_image_usd, total_usd, note}
# Validation
missing_fields: list[str] # Fields the user still needs to provide
required_questions: list[str] # Questions to ask the user before approval
warnings: list[str] # Non-blocking concerns
# Requirements by fidelity mode:
# - fidelity_strict: product_image REQUIRED
# - composite_lock: product_image REQUIRED (source for cutout)
# - fidelity_assisted: product_image optional, warning if missing
# - creative: no requirements
2. Tools (6)
Tool 1: create_marketing_image
Purpose: Generate marketing assets from an approved creative brief.
Use when: The user wants new marketing images — product ads, social content, campaign packs, hero banners. ONLY after preview_generation_plan has returned an approved plan.
Do not use when: The user wants to modify an existing image, manage brand assets, render an HTML layout, or explore options. Never call without an approved plan_id.
class CreateMarketingImageInput(BaseModel):
plan_id: str # REQUIRED — from approved preview_generation_plan
override_prompt: str | None = None # Optional last-minute prompt tweak
override_seed: int | None = None # Override for reproducibility
Returns: Generated images + per-channel exports + metadata envelope. Includes applied_fidelity, applied_color_grading, applied_logo, provenance metadata.
Server behavior: Rejects with ToolError if plan_id is missing, expired, or not approved.
Tool 2: render_marketing_layout
Purpose: Render HTML/CSS templates or raw HTML to pixel-perfect images.
Use when: The user wants designed banners, cards, or layouts with precise typography and positioning — things AI image generation can't do well.
Do not use when: The user wants AI-generated photography or illustrations.
class RenderMarketingLayoutInput(BaseModel):
template: str | None = None # Named template ID (hero_banner, feature_grid, etc.)
html: str | None = None # Raw HTML (if not using template)
variables: dict | None = None # Template variables
brand_kit_id: str | None = None
viewports: list[ViewportSpec] | None = None # Responsive multi-viewport
format: Literal["png", "jpeg", "webp"] = "png"
background: str = "white"
Returns: Rendered image(s) with viewport metadata.
Tool 3: edit_existing_asset
Purpose: Modify, enhance, or transform an existing image.
Use when: The user has an image and wants to change it — edit content, remove background, upscale, apply grading.
Do not use when: The user wants to create something new from scratch.
class EditAction(str, Enum):
EDIT = "edit"
REMOVE_BACKGROUND = "remove_background"
UPSCALE = "upscale"
APPLY_GRADING = "apply_grading"
class EditExistingAssetInput(BaseModel):
image: str # Path to source image
action: EditAction # Enum, not free string
prompt: str | None = None # Edit instruction (for action=edit)
scale: int = 2 # For upscale (2-4x)
color_grading: ColorGradingConfig | None = None
brand_kit_id: str | None = None
preserve_identity: bool = False # When True, use fidelity-strict editing
Returns: Modified image + metadata.
Tool 4: manage_asset_library
Purpose: Create, update, list, and inspect brand kits and product assets.
Use when: The user wants to set up or modify brand identity, register products, manage logos.
Do not use when: The user wants to generate or edit images.
class AssetAction(str, Enum):
CREATE_BRAND_KIT = "create_brand_kit"
UPDATE_BRAND_KIT = "update_brand_kit"
LIST_BRAND_KITS = "list_brand_kits"
REGISTER_PRODUCT = "register_product"
LIST_PRODUCTS = "list_products"
INSPECT = "inspect"
class SubjectType(str, Enum):
PRODUCT = "product"
LOGO = "logo"
PERSON = "person"
PET = "pet"
OBJECT = "object"
class IdentityLock(str, Enum):
NONE = "none"
MEDIUM = "medium"
HARD = "hard"
class ManageAssetLibraryInput(BaseModel):
action: AssetAction # Enum, not free string
# Brand kit fields (for create/update)
name: str | None = None
color_palette: list[str] | None = None
typography: list[str] | None = None
visual_vibe: str | None = None
logo_path: str | None = None
positive_prompt: str | None = None
negative_prompt: str | None = None
safe_use_rules: list[str] | None = None
custom_css: dict[str, str] | None = None
# Product asset fields (for register_product)
product_name: str | None = None
product_image: str | None = None
subject_type: SubjectType | None = None
identity_lock: IdentityLock = IdentityLock.HARD
forbidden_changes: list[str] | None = None
# Inspect
asset_id: str | None = None # For inspect action
Returns: Created/updated asset details, listing, or inspection result.
Tool 5: preview_generation_plan
Purpose: Plan and validate a creative request BEFORE execution. Returns a structured CreativePlan. Also used to approve a draft plan.
Use when: ALWAYS before calling create_marketing_image. Also useful for exploring options, estimating costs, or validating configurations.
Do not use when: Never skip this step for generation workflows.
class FidelityMode(str, Enum):
AUTO = "auto"
CREATIVE = "creative"
FIDELITY_ASSISTED = "fidelity_assisted"
FIDELITY_STRICT = "fidelity_strict"
COMPOSITE_LOCK = "composite_lock"
class PreviewGenerationPlanInput(BaseModel):
# --- Planning mode (create new plan) ---
goal: str | None = None # "Instagram ad for this handbag"
subject_type: SubjectType | None = None
product_image: str | None = None
brand_kit_id: str | None = None
target_channels: list[str] | None = None
fidelity_mode: FidelityMode | None = None # auto = server decides
variant_count: int = 1
color_grading: str | None = None # Preset name
prompt: str | None = None # Specific prompt (optional)
# --- Approval mode (approve existing plan) ---
plan_id: str | None = None # If set, approve/update this plan
approve: bool = False # Flip plan status to "approved"
# --- Fast mode ---
auto_approve: bool = False # Approve immediately if no critical missing fields
Returns: CreativePlan object.
Two modes:
- Plan mode (goal is set, plan_id is None): Creates a new draft plan.
- Approve mode (plan_id is set, approve=True): Validates and approves an existing plan.
Tool 6: inspect_asset
Purpose: Analyze an image using AI vision — describe contents, extract structured attributes, QA check fidelity.
Use when: The user wants to understand an image, verify product fidelity, compare reference vs output, or extract attributes.
Do not use when: The user wants to generate or modify images.
class InspectAssetInput(BaseModel):
image: str # Path to image
question: str = "Describe this image in detail."
structured: bool = False # When True, extract structured attributes
compare_to: str | None = None # Path to reference image for fidelity comparison
Returns: Text description, structured attribute dict, or fidelity comparison report.
3. Resources
All URIs use stable IDs, not display names. Display names live inside the resource payload.
| URI | Description | Replaces |
|---|---|---|
canvas://brand-kits | List all brand kits | brand://kits |
canvas://brand-kits/{kit_id} | Brand kit details | brand://kits/{name} |
canvas://assets | List registered product/logo assets | NEW |
canvas://assets/{asset_id} | Asset details + fidelity rules | NEW |
canvas://templates | List HTML templates + schemas | list_templates tool |
canvas://templates/{template_id} | Template detail + example vars | NEW |
canvas://models | Provider/model catalog with tuning params | models://catalog |
canvas://presets | Channel export presets (69 channels) | platform://specs |
canvas://presets/{preset_id} | Preset detail | platform://specs/{name} |
canvas://policies/fidelity | Default fidelity policies by subject type | NEW |
4. Prompts
Prompt 1: creative_brief (the default intake)
Purpose: The mandatory front door for all creative work. Runs the Creative Brief interview.
You are a creative director at a marketing agency.
A client has a creative request. Before producing anything, run this intake:
1. UNDERSTAND the goal:
- What asset(s) do they need?
- What channels/platforms?
- What's the product/subject?
2. GATHER references:
- Do they have a product photo? (critical for fidelity)
- Do they have a brand kit set up?
- Any style references or mood boards?
- Any specific constraints? (no people, specific colors, etc.)
3. DETERMINE fidelity needs:
- Is there a specific real-world product that must look exact? → fidelity_strict
- Is there a logo that must be pixel-perfect? → composite_lock
- Is this purely creative/conceptual? → creative
4. BUILD the creative direction:
- Mood/vibe
- Color temperature
- Setting/scene
- Camera angle and framing
- Text overlay space needed?
5. CALL preview_generation_plan with everything gathered.
6. PRESENT the plan to the client. Show: workflow, outputs, cost, warnings, questions.
7. WAIT for approval. Do not generate without it.
8. CALL create_marketing_image with the approved plan_id.
Never skip the planning step. Even when the user provides a product photo, still
validate assumptions about channels, mood, fidelity, and creative direction.
Prompt 2: product_hero_campaign
Quick-start for product photography campaigns. Pre-fills subject_type=product, fidelity_mode=fidelity_strict, asks for product photo upfront.
Prompt 3: social_ad_variants
Quick-start for social media A/B testing. Pre-fills variant_count=3, asks about target channels + audience.
Prompt 4: html_creative
Quick-start for designed layouts (banners, cards). Routes to render_marketing_layout instead of create_marketing_image.
5. Compatibility Policy
| Client Type | Prompts | Resources | Notes |
|---|---|---|---|
| Full MCP (Claude Code) | Native prompts | Native resources | Best experience |
| Tool-only clients | prompt__creative_brief etc. | resource__brand_kits_list etc. | Prefixed fallbacks |
FastMCP supports PromptManager and ResourceManager transforms. Enable both. Fallback tool names are prefixed with prompt__ and resource__ to avoid muddying the main tool list.
6. Internal Modules (NOT exposed as tools)
These remain as private functions called by the orchestrator:
_resolve_style_image()— style image resolution_apply_color_grading()— 7 presets + channel math_apply_logo_overlay()— PIL compositing_export_to_spec()— smart upscale + crop_embed_png_metadata()— provenance embedding_resolve_color_grading()— vibe auto-derivevalidate_tuning()— ParamSpec validation_build_brand_css()— CSS variable injection_build_logo_html()— base64 logo for HTMLrender_html_to_image()— Playwright rendering_resolve_fidelity_workflow()— fidelity mode selection_composite_product_into_scene()— cutout + scene + blend- Route selection (provider routing)
What's inside
One plan schema, six tool definitions, eight resource URIs, four prompts, a compatibility policy, and 13 internal modules.
Change this for your project
- Replace
saurabhav88/envious-canvaswith your own repository name - Replace
canvas://resource URIs with your own resource namespace - Replace
openai/gpt-image-1andreplicate/flux-kontext-prowith your model IDs - Replace
69 channelsin presets with your own channel count and specs
Where it goes
Keep it in your repository where the agent or team that needs it will read it.
Worth borrowing
- Requiring a planning step (preview_generation_plan) before any generation call enforces user validation and cost estimation
- Separating HTML layout rendering from AI image generation avoids forcing AI to do precise typography
- Using a CreativePlan object as the central artifact makes the entire workflow auditable and resumable
Related Documents
Media Handling Playbook - Zyeuté v3
Documents upload, storage, optimization, delivery, and edge-case handling for images, videos, and audio in a social app.
Visual Truth Engine: Product-Market Fit & Go-to-Market Strategy
Outlines a product-market fit strategy and go-to-market plan for a B2B SaaS tool that automates proof asset creation for video creators.
Trader ROI Playbook (Codex + CI)
Defines weekly ROI targets, task prioritization lanes, guardrails, and a scorecard template for measuring engineering output per hour.
Devin Triage Playbook
Defines a 7-phase automated triage playbook for Devin to analyze alerts, find root causes, implement fixes, and notify teams.