ferdinandobons/brand-docs
BrandDocs is a set of agent skills that learn your existing Word, PowerPoint and Excel templates and generate new on-brand documents from them. Unlike generic AI document generators, it preserves brand, structure, styles and formulas by construction. Built for Claude Code, Codex and compatible AI agents.
13 Releases
Latest: 2w ago
v0.10.0: hero polishv0.10.0Latest
📋 Changed
- The README hero's three blocks are now equidistant. The full hero refresh shipped inside v0.9.0 without a changelog entry: a redesigned one-to-many visual (one company template, extracted into a verified hexagonal Brand Profile core, fanning out into unlimited on-brand documents, with numbered extract / verify / generate steps), exported as the transparent `assets/hero.webp` the README embeds plus a white-flattened `assets/hero.jpg`, with `assets/hero.svg` as the editable source. This release balances that composition: the template page moved 30 px right, the core 45 px left, and the flow curves, flying brand particles and step labels were re-fit so the three blocks sit at even ~250 px gaps (pixel-measured on the render).
- Full changelog: [CHANGELOG.md](https://github.com/ferdinandobons/brand-docs/blob/main/CHANGELOG.md)
v0.9.0 - the brand-intelligence releasev0.9.0
📦 [0.9.0] - 2026-06-10
- The brand-intelligence release: derived indexes that never lie (rich TOC
- cache, empty rebuilds), multi-template profiles (`extract --blend`), the
- cross-template drift report (`compare-profiles`), a guided authoring surface,
- a local-corpus fidelity benchmark, and a 31-finding general-review hardening
- wave on top.
🐛 Fixed
- General-review wave (multi-agent, 31 confirmed findings). Engine: the
- heading-less generation now collapses a bare multi-paragraph outline TOC's
- FULL span to an empty field (the plain writer used to leave the template's
- demo entries and orphan the end fldChar - a regression of the rich-TOC
- delta); pptx and xlsx extraction now parse the theme `a:fontScheme` latin
- typefaces instead of hardcoding `latin=null` (the docx extractor already
- did); `schema.validate` returns problems instead of raising on a
- hand-edited blend ledger with mixed-type entries; profile JSON/sidecar
- + 39 more
✨ Added
- Local-corpus fidelity benchmark (REFLECTIONS P3). New
- `scripts/corpus_benchmark.py` walks a corpus of REAL templates that lives
- outside the repository (and refuses one inside it), runs
- extract -> verify -> brand-agnostic probe generate -> QA per template in a
- throwaway directory, and writes a dated `report.{md,json}` next to the
- corpus with the LibreOffice-vs-Word caveat stated in the header. The probe
- input is typed blocks only (no styles, colors, fonts), so the corpus
- measures the engine without ever tuning it; `documentation/DEVELOPMENT.md`
- + 55 more
v0.8.1: hardening patchv0.8.1
📦 Highlights
- A post-0.8.0 hardening patch. Generated bytes are unchanged for well-formed templates and profiles (frozen byte-identity anchor verified).
- Plugin onboarding fixed: every skill/command doc now teaches `python scripts/cli.py ...` - a launcher that resolves the engine root from the skill folder AND the repo/plugin root (`BRAND_DOCS_ROOT` overrides). Fresh plugin sessions no longer trip on a wrong path.
- Example pptx imports in Keynote: python-pptx omits `p:notesMasterIdLst` when speaker notes are authored; strict importers rejected the package. The builder now repairs it deterministically at build time.
- Engine hardening (with regression tests): caption-index refresh validates both field bounds (a corrupted inventory could corrupt the body via negative indexing); `role_id` validates its own composition; border-apply refuses mislabeled sides and narrows its catches; set-only-when-unset guards treat empty attributes as unset. A frozen `CHECK_REGISTRY` pins the QA check-id vocabulary behind an AST-guarded test.
- Example docx visual fixes from a page-by-page render audit: clean solid cover band, landscape appendix no longer inherits the two-column layout, readable white table headers, repeating header rows on page-spanning tables, balanced two-column synopsis.
- Honest speed expectation in the README: first run on a new template up to ~15 minutes end to end with an agent; every later document takes seconds - still a fraction of hand-formatting, with a faithful file instead of an approximate one.
- Full detail: [CHANGELOG.md](https://github.com/ferdinandobons/brand-docs/blob/main/CHANGELOG.md#081---2026-06-10)
v0.8.0: the learning releasev0.8.0
📦 Highlights
- The profile now learns. Three channels close the loop, every one fail-closed and advisory until an explicit `--accept`:
- From its own QA findings: every `generate` persists a cross-run report; the `learn` verb distills recurring findings into shell-frozen overrides, and the new `propose-overrides` verb lets the model correct the ambiguous remainder through the same single validated sink, with an `override_applied` audit finding for every live correction.
- From the model's judgement: the L2 visual-audit verdict persists (and soundly short-circuits byte-identical re-renders), ambiguous WARNINGs get triaged, faked headings (a body-style line that visibly acts as a heading) are detected as `pseudo_headings` and can be promoted onto a real heading role, and off-theme brand accents become addressable run colors via palette aliases (the model names, the engine byte-copies the captured ref).
- From the user: the `refine` verb turns end-of-generation feedback (text or a screenshot) into a validated comprehension delta for future generations.
- Full detail: [CHANGELOG.md](https://github.com/ferdinandobons/brand-docs/blob/main/CHANGELOG.md#080---2026-06-10)
v0.7.0 - brand appearance, model-driven color, cover & caption-index fidelityv0.7.0
📦 [0.7.0] - 2026-06-09
- Brand-fidelity release: the engine now follows a template's real per-run typography
- (font, size, color), applies model-named brand colors, fills content-control covers
- faithfully, and regenerates caption indexes from the new content. Schema stays 1.2.0
- (additive); profiles from earlier versions keep working unchanged.
✨ Added
- Brand typography capture (font family + size + color). Extraction now captures
- the template's dominant DIRECT run typography - the real visible font, font size
- and run color a designed template applies per-run (e.g. Roboto 16pt) rather than
- via the named styles or theme - into the reserved `role.appearance` field and the
- additive `theme.fonts.body` (font/size) and `theme.text.body` (color). Generation
- applies all three as direct run formatting through the resolver (paragraphs, list
- items, captions, quotes, callouts, table cells, and hyperlink runs), so a generated
- document renders in the template's real font, size and color instead of falling
- + 37 more
🐛 Fixed
- Colored hyperlink runs now write `w:color` at the schema-correct `CT_RPr` position
- (before `w:u` / `w:sz` / `w:vertAlign`) instead of appending it last, so an
- underlined colored link is conformant OOXML; a theme-token link with no resolved hex
- emits `themeColor` only (no stray `w:val="000000"` that would paint it black).
v0.6.2
🐛 Fixed
- DOCX `extract` and `generate` no longer crash on templates whose section measures are non-integer twips (e.g. `1440.0000000000002` in `w:pgMar` / `w:pgSz`, emitted by some editors). python-docx parses measures with `int()` and raises the moment any code touches the value, including its own internals (`Document.add_table` derives the table width from `section.left_margin`). The shell's section measures are now sanitized in place (sub-twip rounding, page geometry visually identical) and every section-length read tolerates the malformed value via a raw-twips fallback.
🧪 Tests
- `MalformedSectionMeasureTest`: the section-length helpers tolerate the bad value, `sanitize_section_measures` repairs it in place, and a generate with a table block (the exact crash path) survives a malformed margin.
v0.6.1
🐛 Fixed
- The QA gate now verifies a `number_format` role's mask against the SHELL's
- actually-used formats (the shell-backed peer of the schema's intra-profile
- check), so a fabricated/hand-edited mask is caught at verify time, never applied.
- A `table`/`KPI`/`SmartArt` block rendered against a profile with no matching role
- no longer falls back to the default style SILENTLY: it surfaces an INFO
- `style_fallback` so the missing brand style is visible in QA (the content still
- renders).
📋 Changed
- Removed dead parameters (no behavior change): `run_qa`'s never-read `mode`, the
- docx `_write_block` `profile` arg, and the xlsx `_resolve_named_target` `findings`
- arg.
🧪 Tests
- Closed the review's remaining coverage gaps: strict-mode promotion of
- `visual.ocr_degraded` to an error, `_ocr_png` timeout/OSError degradation, the
- Quick-Look-absent render degrade, the QA-gate fabricated-mask rejection, and the
- `style_fallback` path.
v0.6.0
✨ Added
- Visual QA runs by default and installs in one step. The renderer probe is now
- FUNCTIONAL-first: a LibreOffice that actually renders is usable even if its macOS
- code signature was knocked loose by an update/quarantine removal (no re-sign
- needed), so the visual gate is no longer falsely disabled. `scripts/setup_visual_qa.sh`
- auto-detects the platform package manager and installs LibreOffice + Poppler
- (+ optional Tesseract); the README/INSTALLATION reframe visual QA as a standard,
- on-by-default part of the QA step.
- An aggregate OCR time budget so a many-page document cannot turn a deep/strict
- + 1 more
🐛 Fixed
- Security - Excel formula injection: author content starting with `=` became a
- LIVE formula (`=WEBSERVICE`/`=HYPERLINK`/DDE) in the generated workbook, breaking
- the "formulas live only in the shell" invariant. It is now neutralized to a TEXT
- cell (verbatim, never executed) and surfaced; the QA gate also fails closed on any
- output formula the shell did not have.
- Security - hyperlink scheme allowlist: docx/pptx now refuse `file:`/
- `javascript:`/`data:`/`smb:` link targets (the text is kept), so untrusted content
- cannot wire a hostile link into an on-brand file.
- + 12 more
📋 Changed
- Removed verified-dead helpers and corrected stale docstrings/docs: the docx TOC
- and the pptx charts/SmartArt/KPI/images are native now (not "deferred"), and
- `number_format`/`named_range` are first-class resolver types.
v0.5.0
✨ Added
- Word `toc` blocks render natively. The `toc` block was the last block type
- that degraded instead of rendering; it now authors a real, updateable outline
- table-of-contents field. If the shell already carries an outline TOC the block
- defers to it (refreshed in place, never a duplicate); otherwise it authors a
- native outline TOC field at the block's position, with its visible cache filled
- from the generated headings and the field marked dirty + `updateFields` so Word
- rebuilds it on open. It defers only to an OUTLINE TOC, so a shell shipping only a
- table-of-figures still gets its requested table of contents. Byte-idempotent.
- + 13 more
v0.4.0
✨ Added
- The reusable-fragment registries (`components` / `sections`) are now
- populated by the model through the fail-closed `comprehend` boundary - no
- hardcoded catalog. A `comprehend` proposal may carry a `fragments` list (each
- `{ref, kind: component|section, purpose?, blocks}`); `merge` validates it
- fail-closed (every block parses as a known IID primitive; a nested
- `component`/`section` ref must resolve to another fragment proposed in the same
- comprehension; `(kind, ref)` is unique; cyclic references are rejected) and, on
- a clean pass, DERIVES the entries into `profile['components']`/`['sections']` -
- + 27 more
v0.3.0
✨ Added
- A `chart` block is now authored as a native chart on both Word and PowerPoint
- (a real DrawingML `c:chart`: an inline `w:drawing` on docx, a `graphicFrame` on
- pptx), no longer flattened to body text. `bar`/`column`/`barh`/`line`/`area`/`pie`/
- `doughnut` map to the matching chart type (unknown -> clustered column, surfaced as
- INFO); series/categories/title come from the block, and the chart inherits the
- document/deck theme's accent colors so it is on-brand by construction. A
- multi-series pie/doughnut surfaces a truncation WARNING; an empty/all-non-numeric
- chart degrades loudly. A shared `ooxml.chart` builds the docx chart with INLINE
- + 19 more
🐛 Fixed
- General correctness + quality review (multi-agent, adversarially verified):
- Word/PPTX tables no longer drop multi-run column headers. A header cell
- authored with rich runs (e.g. plain text + a bold unit) kept only its first
- run through `Table.from_dict`; every run is now preserved (and the loose
- `{"runs": [...]}` / `{"text": "..."}` / run-list / string shapes a body cell
- accepts are accepted for columns too).
- PowerPoint body text on a placeholderless layout degrades loudly instead
- of vanishing silently (a `block_degraded` WARNING is now recorded).
- + 12 more
📋 Changed
- `component_survival` now has a single source of truth. The pptx generator's
- own pre-reconcile, drop-to-zero variant was removed; the QA gate's
- `check_component_survival` (which re-reads the shell and output independently,
- for all three formats, on any count decrease) is the sole emitter. This ends the
- duplicate, differently-worded `component_survival` findings a pptx run produced.
BrandDocs v0.2.0v0.2.0
✨ Added
- `doctor` is now a preflight gate, not just a report: it exits nonzero
- when a required Python dependency is missing, so a broken environment
- fails before generation instead of mid-run.
- `doctor --json` prints the machine-readable dependency/renderer probe;
- `doctor --fast` skips the slow LibreOffice render probes (visual QA is
- marked "not probed") for a quick check.
- PowerPoint now expands reusable `components` / `sections` fragments,
- matching the Word vertical: a profile-defined fragment inlines
- + 6 more
📋 Changed
- The destructive-action confidence floor (>= 0.5) is now applied
- uniformly at every reconcile site across Word, PowerPoint, and Excel
- from a single source of truth, so a low-confidence delete is downgraded
- to keep-with-warning consistently (previously only some sites enforced
- it).
- PowerPoint now honors the profile-resolved body placeholder index
- (`ph_idx`) when filling body content, instead of always assuming the
- first placeholder.
- + 14 more
🐛 Fixed
- Excel no longer crashes when a named region's first row straddles a
- merged banner: writes to a merged-slave cell are guarded (only the merge
- anchor is writable) and the skipped value surfaces as a `block_degraded`
- warning instead of raising or being lost.
- PowerPoint no longer silently drops Component / Section / Toc / Divider
- blocks it has no native writer for: each now emits a visible
- `block_degraded` warning, honoring the "never drop content silently"
- invariant.
- + 3 more
BrandDocs v0.1.0v0.1.0
📦 [0.1.0] - 2026-06-07
- Initial public alpha release.
✨ Added
- `brand-docx`, `brand-pptx`, and `brand-xlsx` skills for same-format
- generation from Word, PowerPoint, and Excel templates.
- Shared Brand Profile engine for extracting template styles, structure,
- layouts, named ranges, formulas, media, and reusable OOXML artifacts.
- Deterministic QA for resolver targets, allowed styles/layouts/ranges,
- residual template text, table integrity, formula preservation, language
- checks, and artifact drift.
- Optional visual QA with renderer dependency preflight, visual manifests,
- + 4 more
📦 Notes
- BrandDocs is alpha software. DOCX is the reference vertical; PPTX and XLSX
- share the same engine and are intentionally catching up through the eval
- suite and visual repair workflow.
- [0.1.0]: https://github.com/ferdinandobons/brand-docs/releases/tag/v0.1.0
