| title | Unified Branding Agent — Usage Guide | |
|---|---|---|
| description | Complete guide for using the unified branding agent to apply category-aware branding to documents | |
| file_type | documentation | |
| version | 1.0.2 | |
| created_date | 2026-05-29 | |
| last_updated | 2026-08-21 | |
| category | docs | |
| owners |
|
Document Version: 1.0.1 Last Updated: 2026-06-19 Related Issues: #555 (Wave 4E Implementation)
The Unified Branding Agent automates the application of category-aware branding (headers, footers, and badges) to Markdown documents across the repository.
It reads from the canonical branding configuration (config/footers.config.yaml and schemas/branding-schema.json) with a legacy fallback for older automation paths, and applies consistent branding rules based on:
- Document category (explicitly in frontmatter or inferred from file path)
- Predefined footer templates per category
- Frontmatter metadata (title, version, owners, dates)
- Fallback rules for missing metadata
- Node.js 18+ (for ES modules support)
js-yamlpackage (already in project dependencies)minimistpackage (already in project dependencies)
# Check that the agent file exists
ls -la .github/scripts/agents/branding-unified.agent.js
# Check configuration files exist
ls -la config/footers.config.yaml
ls -la schemas/branding-schema.jsonnode .github/scripts/agents/branding-unified.agent.js <file-path> [options]| Argument | Description | Example |
|---|---|---|
<file-path> |
Required. Path to file relative to project root | docs/guide.md |
| Option | Short | Description | Default |
|---|---|---|---|
--dry-run |
-d |
Preview changes without writing | true |
--apply |
— | Apply changes to file | false |
--verbose |
-v |
Show detailed output | false |
--infer-metadata |
— | Infer missing frontmatter fields | false |
--help |
-h |
Show help message | — |
# Default: dry-run shows what would change
node .github/scripts/agents/branding-unified.agent.js docs/guide.md
# Output:
# 📄 File: docs/guide.md
# Status: success
# Category: docs
#
# ✅ Changes:
# - Updated header
# - Updated footer# --apply flag writes changes to the file
node .github/scripts/agents/branding-unified.agent.js docs/guide.md --apply
# Output includes "Status: applied"# Shows detailed processing information
node .github/scripts/agents/branding-unified.agent.js docs/guide.md --verbose# Automatically fills in missing required fields with sensible defaults
node .github/scripts/agents/branding-unified.agent.js docs/guide.md --apply --infer-metadata
# Output:
# ✅ Changes:
# - Set title to: guide
# - Set category to: docs
# - Set file_type to: documentation
# - Set last_updated to: 2026-05-29node .github/scripts/agents/branding-unified.agent.js --helpThe agent determines the document's category using hybrid inference:
- Check frontmatter — If
category:field is present and valid, use it - Check file path — Match path against predefined patterns (in priority order)
- Fallback — Default to
docscategory if no match
Example Category Inference:
# File: docs/governance/policy.md
# Frontmatter: (category field present)
# Step 1: Check frontmatter
category: governance # ✅ Found → Use "governance"# File: agents/labeling.agent.md
# Frontmatter: (no category field)
# Step 1: Check frontmatter → not found
# Step 2: Check path patterns
# Pattern: ^agents\/.*\.(?:md|agent\.md)$ → MATCH
# Use: "agents" # ✅ InferredCheck that required fields are present for the category:
- Required fields (all categories):
title,description,file_type,category - Optional but recommended:
version,created_date,last_updated,owners,tags,status,stability
Validation errors are reported as warnings and don't block processing.
# Example: missing 'description'
---
title: "My Document"
# description: MISSING
file_type: documentation
category: docs
---
# Output:
# ⚠️ Warnings:
# - Missing required field: descriptionFor categories with header_behavior: "required", the agent generates a header including:
- Document title
- Category badge (e.g.,
[docs]) - Status (active, draft, deprecated)
- Version (if present)
- Owners (if present)
- Last updated (if present)
Example Generated Header:
---
title: API Documentation
description: Complete API reference
category: docs
version: 2.0.0
owners: ["@ashshaw", "team@lightspeedwp.agency"]
last_updated: "2026-05-29"
---
# API Documentation
**Category**: [docs] · **Status**: Active · **Version**: 2.0.0
**Owners**: @ashshaw, team@lightspeedwp.agency · **Last Updated**: 2026-05-29
---
## API Endpoints
Content begins here...The agent selects a footer template based on:
- Explicit selection —
footer_id:field in frontmatter (highest priority) - Category default —
default_footerfrom category configuration - Fallback —
lightspeed-standardif category has no default
Footer templates may contain variables that are substituted:
# Example footer template with variable:
audit-footer:
template: |
---
🔍 Audit report generated {audit_date}
variables:
audit_date: "Date the audit was performed (YYYY-MM-DD)"Variable Substitution:
# Frontmatter:
---
audit_date: "2026-05-28"
---
# Rendered footer:
---
🔍 Audit report generated 2026-05-28- Dry-run mode (default): Preview output, no changes written
- Apply mode (
--apply): Write changes to file and report success
Defines all categories and footer templates:
version: "1.0.0"
categories:
docs:
name: "Documentation"
default_footer: "lightspeed-standard"
allowed_footers: ["lightspeed-standard", "lightspeed-brief"]
header_behavior: "required"
footer_behavior: "required"
footers:
lightspeed-standard:
id: "lightspeed-standard"
template: |
---
*Built by 🧱 LightSpeedWP*The repository validator now treats missing branded footers in changed Markdown as a failure and can backfill them from the category default via npm run validate:footers -- --fix.
Run the validator after bulk edits or agent changes to make sure changed docs are not left unbranded:
npm run validate:footersComprehensive JSON Schema for validation and IDE autocomplete.
Defines frontmatter field types and constraints.
| Category | File Pattern | Header Required | Footer Required | Default Footer |
|---|---|---|---|---|
docs |
docs/**/*.md |
Yes | Yes | lightspeed-standard |
agents |
agents/**/*.md |
Yes | Yes | ai-ops-standard |
instructions |
instructions/**/*.md |
Yes | Yes | standards-footer |
ai-ops |
docs/**/*governance*.md |
Yes | Yes | ai-ops-standard |
prompts |
prompts/**/*.md |
Optional | Optional | ai-ops-standard |
schema |
schemas/**/*.md |
Yes | Yes | schema-footer |
audit |
.github/reports/**/*.md |
Yes | Yes | audit-footer |
research |
research/**/*.md |
Yes | Yes | research-footer |
workflow |
.github/workflows/**/*.md |
Yes | Yes | ai-ops-standard |
awesome-copilot |
awesome-copilot/**/*.md |
Yes | Yes | copilot-footer |
governance |
governance/**/*.md |
Yes | Yes | governance-footer |
test |
test/**/*.md |
Optional | Optional | lightspeed-standard |
utility |
.github/scripts/**/*.md |
Optional | Optional | utility-footer |
readme |
README.md |
No | Yes | lightspeed-standard |
issue-template |
.github/ISSUE_TEMPLATE/*.md |
No | Optional | issue-footer |
pull-request-template |
.github/PULL_REQUEST_TEMPLATE/*.md |
No | Optional | pr-footer |
File: docs/getting-started.md
---
title: "Getting Started"
description: "Quick start guide for the project"
file_type: documentation
category: docs
version: "1.0.0"
owners: ["@ashshaw"]
last_updated: "2026-05-29"
---
## Installation
To install...Command:
node .github/scripts/agents/branding-unified.agent.js docs/getting-started.md --applyResult:
The agent:
- ✅ Infers category:
docs(already in frontmatter) - ✅ Validates frontmatter: All required fields present
- ✅ Generates header with metadata badges
- ✅ Selects footer:
lightspeed-standard(default for docs) - ✅ Writes file with header and footer
Output:
---
title: "Getting Started"
description: "Quick start guide for the project"
file_type: documentation
category: docs
version: "1.0.0"
owners: ["@ashshaw"]
last_updated: "2026-05-29"
---
# Getting Started
**Category**: [docs] · **Status**: Active · **Version**: 1.0.0
**Owners**: @ashshaw · **Last Updated**: 2026-05-29
---
## Installation
To install...
---
*Built by 🧱 LightSpeedWP with ☕, 🚀, and open-source spirit!*
[🔗 Website](https://lightspeedwp.agency) · [📧 Contact](https://lightspeedwp.agency/contact) · [👥 Contributors](https://github.com/lightspeedwp/.github/graphs/contributors)File: agents/my-agent.md (no frontmatter)
# My Agent
This is an agent specification...Command:
node .github/scripts/agents/branding-unified.agent.js agents/my-agent.md --apply --infer-metadataResult:
The agent:
- ✅ Infers category:
agents(from path pattern) ⚠️ Validates frontmatter: Missing required fields- ✅ Infers metadata: title, category, file_type, last_updated
- ✅ Generates header with inferred metadata
- ✅ Selects footer:
ai-ops-standard(default for agents) - ✅ Writes file with frontmatter, header, and footer
Command:
node .github/scripts/agents/branding-unified.agent.js docs/guide.md --verboseOutput:
📄 File: docs/guide.md
Status: success
Category: docs
✅ Changes:
- Updated header
- Updated footer
⚠️ Warnings:
- Missing optional field: owners
# Process all docs
for file in docs/**/*.md; do
node .github/scripts/agents/branding-unified.agent.js "$file" --apply
done
# Process all agents
for file in agents/**/*.md; do
node .github/scripts/agents/branding-unified.agent.js "$file" --apply
done# Dry-run on all markdown files
find . -name "*.md" -type f | while read file; do
node .github/scripts/agents/branding-unified.agent.js "$file"
done
# Apply to all (careful!)
find . -name "*.md" -type f | while read file; do
node .github/scripts/agents/branding-unified.agent.js "$file" --apply
done❌ Error: File not found: docs/nonexistent.md
Solution: Check that the file path is correct and relative to project root.
❌ Error: Failed to parse frontmatter: mapping values are not allowed here...
Solution: Check YAML syntax. Use a YAML validator: https://www.yamllint.com/
⚠️ Warnings:
- Unknown category: invalid_category
Solution: Use one of the 16 valid categories. See category reference table above.
- Warnings (
⚠️ ): Missing optional fields, non-critical issues. Processing continues. - Errors (❌): File not found, invalid YAML, etc. Processing stops.
The agent can be imported and used programmatically in other scripts:
import {
parseFrontmatter,
inferCategory,
validateFrontmatter,
generateHeader,
getFooter,
processBrandingDocument,
} from "./.github/scripts/agents/branding-unified.agent.js";
// Parse a file
const content = fs.readFileSync("docs/guide.md", "utf-8");
const { frontmatter, body } = parseFrontmatter(content);
// Infer category
const category = inferCategory("docs/guide.md", frontmatter, config);
// Validate
const errors = validateFrontmatter(frontmatter, category, config);
// Generate
const header = generateHeader(frontmatter, category, config);
const footer = getFooter(category, frontmatter, config);
// Or use the all-in-one processor
const result = processBrandingDocument("docs/guide.md", {
apply: true,
infer_missing_metadata: true,
});node: no such file or directory: .github/scripts/agents/branding-unified.agent.js
Solution: Verify file exists and you're in the project root.
Error: Branding config not found: {path}/config/footers.config.yaml
Solution: Verify config/footers.config.yaml exists in project root.
Error: Cannot find module 'js-yaml'
Solution: Install dependencies: npm ci
-bash: .github/scripts/agents/branding-unified.agent.js: Permission denied
Solution: Add execute permission: chmod +x .github/scripts/agents/branding-unified.agent.js
# Preview changes before applying
node .github/scripts/agents/branding-unified.agent.js file.md
# Review output, then apply
node .github/scripts/agents/branding-unified.agent.js file.md --applyAlways include the 4 required fields:
---
title: "Document Title"
description: "Brief description of content"
file_type: "documentation"
category: "docs"
---If your file is in a standard location, you don't need to specify category:
# File: docs/guide.md
---
title: "Guide"
description: "A guide"
file_type: "documentation"
# category: omitted — inferred from path
---Prefer 3–4 line footers. Very long footers disrupt readability.
For dated content, use variables instead of hardcoding:
---
audit_date: "2026-05-28"
---
# Then footer template substitutes {audit_date}name: Apply Branding to Markdown Files
on:
pull_request:
paths:
- "**.md"
jobs:
branding:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Apply branding to changed files
run: |
git diff --name-only HEAD~1 | grep '\.md$' | while read file; do
node .github/scripts/agents/branding-unified.agent.js "$file" --apply
done
- name: Commit changes
if: success()
run: |
git config user.name "Automation"
git config user.email "automation@lightspeedwp.agency"
git add .
git commit -m "Apply unified branding" || echo "No changes"- BRANDING_CONFIG_SPEC.md — Complete configuration specification
- Issue #555 — Implementation details
- Wave 4D: Schema & Config — Configuration system
- Wave 4C: Audit — Current state analysis
For issues, questions, or feature requests:
- Check this documentation
- Review BRANDING_CONFIG_SPEC.md
- Open an issue on GitHub: https://github.com/lightspeedwp/.github/issues
Maintained by the 🤖 LightSpeedWP Automation Team