Portability
Requirements that keep brand assets useful across platforms and teams.
Documentation for BrandBuilder 3.0.1. Official release and exact skill asset.
Build the same kit from the same source on Claude, Codex, and a bare checkout. Probe local capabilities first and record explicit skips for optional renderers.
For asset handoff, use the Asset Language terms and logos/asset-aliases.json: preferred descriptive names and approved original paths deliver identical bytes. Keep the original paths when migrating consumers that pin direct asset URLs.
The capability model
Do not assume. Probe once, at the start, and record what you found:
python3 templates/probe.pyIt prints a capability block and writes <kit>/qc/probe.json. Everything
downstream routes off that. A missing tool gets named in VERIFY.md as a skip
with a reason; it never gets silently substituted, and it never gets quietly
skipped.
Three capability tiers, and what each can still finish:
| Tier | What is present | What you get |
|---|---|---|
| Core | Python 3.8+, coloraide, jsonschema, and the standard library | brand.json, all tokens, the Next.js binding, enforcement, the guidelines page, the specimen, the manifest, verify.py and the full glyph gate |
| Raster | Core, plus a rasteriser and Pillow for required compositing | Everything above, plus PNG exports and the favicon set; a measured ICO writer adds the multi-entry .ico |
| Full | Raster, plus headless Chromium | Everything above, plus the brand guide PDF and the QC contact sheets |
The Core tier must always succeed. If a step cannot run at Core, it is
written wrong. That is why validate_glyph.py carries its own rasteriser and
why no gate depends on an agent being able to view an image.
Authoritative PNG logos follow the same rule. Core accepts only non-interlaced RGBA8 and compares exact binary topology using the owner-approved alpha or luminance mask tied to the current source hash. Bound passive SVGs are verified by exact embedded bytes; JPEG and WebP cannot bind a logo variant. Raster and Full independently rerender every logo PNG and compare platform PNGs plus ICO and ICNS frames with their declared verified masters, but they do not replace the Core authority verdict. Every generated derivative carries its source ID, source hash, variant, and transformations in logos/provenance.json, so capability handoffs cannot silently substitute another mark.
Vision is a bonus, never a gate
The house rule is still "look at every rendered artifact before shipping it", and an agent that can see images must still open the contact sheets. But no build is blocked on somebody having eyes, because on Codex nobody does.
Every quality question therefore has a measured form:
| The question | The measured answer |
|---|---|
| Is the mark correct? | validate_glyph.py, all numbers, zero external tools |
| Does it survive a favicon? | component and counter counts at 32 and 16 px |
| Is the guide usable? | qc_render.py ink coverage, density, largest empty run, folio presence |
| Do elements split across pages? | qc_paginate.py, DOM-level, exact |
| Is the contrast legal? | coloraide at build time, never a typed number |
When a rendered artifact cannot be produced at all, say so in VERIFY.md and in
the handoff. "The PDF was skipped because Chromium is unavailable" is a fine
outcome. "The PDF looks good" from an agent that never rendered it is not.
Python
- Invoke as
sys.executablefrom inside a script and aspython3from a shell, falling back topythonwhenpython3is absent. On Windows, usepythonwhenpython3is unavailable. - Target 3.8. No structural pattern matching, no
tomllib, no|unions in annotations. - Open every file with an explicit
encoding="utf-8"and, on write,newline="\n". Windows defaults to cp1252 and CRLF, and both corrupt a checksummed manifest. - Install optional renderer dependencies with
pip install --user; if installation fails, drop to a lower tier and record the skip. Missingcoloraideorjsonschemablocks Core and must be fixed before building. - Core work requires
coloraidefor measured color andjsonschema==4.17.3for registry validation. If either is missing, the probe blocks before writing a capability report. Font contract validation requires fontTools, and WOFF2 inspection also requires Brotli. Raster palette evidence requires Pillow. Report a missing required contract dependency explicitly; do not substitute or publish partial evidence.
Shell and paths
- Build every path with
os.path.join. Never interpolate/into a path. - Never depend on the working directory. Resolve relative to
os.path.dirname(os.path.abspath(__file__)). - Do not pipe, glob or chain in
subprocess. Pass an argument list. - Do not assume a POSIX utility exists.
find,sed,md5sumandunzipare all absent somewhere. - Some sandboxes cannot delete files. Prefer overwrite-in-place to delete-then-write, and if a directory has to be replaced, write the new files over the old ones rather than removing the tree first.
External tools
Probe for every one of these and route to the first that answers:
| Job | First choice | Then | Then |
|---|---|---|---|
| SVG to PNG | rsvg-convert | resvg | the bundled rsvg-convert.js on Node with @resvg/resvg-js |
| Multi-entry ICO | magick | convert | Pillow, with the per-size PNGs already rendered |
| headless Chromium via Playwright | none: skip and record it | ||
| PDF inspection | pikepdf | pdffonts | skip |
Two specific traps, both of which have cost a run:
ImageMagick 6 has no magick. It ships convert. A probe that tests only
for magick reports the ICO step as a skip on every ImageMagick 6 host, and a
skip reads as "not applicable" rather than "your favicon is broken".
Google Fonts is a trap, not a build tool. Fonts are bundled in the kit and ordinary generation stays offline. When an approved fixed face is absent, use the explicit controlled ingestion command with an authoritative HTTPS or controlled local source, expected hash, license evidence, contained destination, and atomic validation before the build begins.
Network
Assume there is none. Nothing in routine generation, verification, documentation, site preparation, or release packaging may require a network call. Controlled font ingestion is a separate operator-invoked preparation action and never runs implicitly.
Every generated kit also carries the exact pinned BrandBuilder distribution under enforcement/distributions/. Each distributed skill contains SOURCE_REVISION, which binds generated provenance to the BrandBuilder commit that produced the release without consulting the consumer repository. enforcement/consumer-contract.json records the distribution filename, compiler version, contained path, and SHA-256. A fresh consumer verifies and uses these delivered bytes before considering an authorized exact-version network recovery. It never installs an unspecified latest release.
Frontmatter and entry points
Different hosts read different things, so the skill ships both:
SKILL.mdwith frontmatter limited toname,description,license,compatibility,metadataandallowed-tools. Anything else,user-invocablein particular, hard-fails claude.ai and Skills-API upload validation.AGENTS.mdat the root, plain Markdown with no frontmatter at all, saying the same thing in the same order. This is what a Codex or an agent working from a bare checkout reads. It must stay in step withSKILL.md: when the routing table changes, both change.
The same contextual Author, Implementation, and Audit policy appears in both entry points because AGENTS.md is regenerated from SKILL.md. Consumer kits carry a separate concise governed block that points to their exact generated IMPLEMENTATION.md and consumer contract.
Write instructions as file paths and shell commands, not as tool names. "Read
references/08-glyph-construction.md" works everywhere. "Use the Read tool on"
works in one product.
The single most portable habit
Prefer a script that a human could run over an instruction a model has to
follow. python3 templates/build_kit.py . behaves identically on every
provider. A paragraph telling the agent what order to do six things in does not.
Every time a step turns out to be provider-dependent, the fix is to move it into a template and have the prose call the template.
Check the target host
After importing a generated icon, inspect the host's own packaging and display: Apple app icon guidance, Windows icon design, and maskable web icons describe different targets. A kit source file proves what was delivered, while a host preview proves how that exact file appears there. For interface behavior, preserve native controls and labels described by HTML semantics or the target platform's equivalent. This task does not require redrawing the approved master.