CtrlK
BlogDocsLog inGet started
Tessl Logo

metis-strategy/metis-pptx

Create or edit PowerPoint presentations. Dual-mode skill: (1) Editing mode preserves existing templates via Open XML unpack/edit/repack when an existing .pptx is provided. (2) Generation mode creates new Metis-branded decks from a design system with 36 composable components and 5 layout grids. Includes brand extraction for client decks and visual QA via PowerPoint COM. Triggers on deck, slides, presentation, PPT, or any .pptx request.

84

Quality

84%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files
name:
metis-pptx
description:
Create or edit PowerPoint presentations. When an existing .pptx file is provided or referenced (by attachment, file path, or description), use the template-preserving editing workflow. When no existing file is involved and a new Metis-branded deck is needed, use the generation workflow. Also trigger on "slides," "deck," "presentation," "PPT," or any .pptx request.

PowerPoint Skill — Metis Strategy

0. Mode Gate

Before doing anything else, determine which workflow to use.

Does an existing .pptx file need to be preserved?

ConditionMode
User provides, attaches, or references an existing .pptx file (by path, filename, or description)Editing → Section 1
No existing file; user wants a new Metis-branded deckGeneration → Section 2

Examples:

  • "Edit this deck" → Editing
  • "Add slides to client_deck.pptx" → Editing
  • "Update the content in proposal.pptx" → Editing
  • "Use the Aflac template" → Editing
  • "Take our proposal from last week and update it" → Editing
  • "Build me a proposal deck" → Generation
  • "Create a Metis pitch for Nationwide" → Generation
  • "Make slides for the offsite" → Generation

The test is simple: does a .pptx file exist that we need to preserve? If yes, use Editing. If no, use Generation.


0.5 The Slide Skeleton — default for every content slide

Every polished Metis content slide uses the same five slots. Before picking a component, the layout must contain all five.

SlotPurposeTreatment
1. TitleOne-line claim in brand-primary28pt bold, Dark Navy #20206E, top of slide
2. SubtitleThe "so-what" in plain language13pt italic, neutral gray, directly below title
3. BodyA visual structure that expresses the thoughtPulled from the Timesaver library (see §0.6), or built as a bespoke metaphor — never plain bullets on white
4. Takeaway barSingle bold mantra that ties body to messageFull-width Dark Navy bar with optional Mint left accent, ~0.65" tall, white/mint text, near bottom (y≈6.05")
5. Brand frameLogo + page number + green arrowInherited automatically from 1_Title Only master layout

The takeaway bar is required for content slides. If you can't write one bold mantra that summarizes the slide, the slide isn't tight enough yet. Real examples:

  • "Every function builds on the same structure. IT's job is to build the house — once."
  • "AI is the revolution. The house is how it compounds — turning IT from cost center into growth partner."
  • "One customer experience. One operating system. One team."

The brand frame, title placeholder, and footer all come from master.pptx's 1_Title Only layout — never re-draw them.


0.6 Concept-to-Shape — Timesaver visual library

Metis Strategy slide design has two co-equal paths, both grounded in the same brand system (metis-brand.md). Choose per slide based on what the content needs — neither path is the default or the fallback for the other:

  • Path A — Component recipes (references/patterns.md + references/metis-brand.md) 36 brand-agnostic component patterns with exact python-pptx code recipes.
  • Path B — Timesaver visual library (this section) 260 pre-designed slide structures spanning every chart type, framework, and narrative arc Metis Strategy uses. Catalog: references/timesaver_index.md.

Both paths use the same colors, fonts, master, and frame. The decision is structural: does this content live naturally in cards/columns/boxes, or does the shape itself express the thought?

How to choose between the paths

Path A (patterns.md) and Path B (Timesaver) are co-equal candidate libraries — neither is the default, neither is the fallback. Every content slide is a candidate for either, and the right choice depends on what the slide's structural relationships actually require.

The choice is not made by reading the slide title and pattern-matching keywords. It's made by looking at candidates from both libraries against the slide's articulated structural needs, and picking the one that fits best. If you find yourself deciding "this is enumeration, so Path A" without ever loading a Timesaver PNG, you've shortcut the choice.

Operationally, this means every content slide goes through:

  1. Articulate structural needs from the slide content. (Done before any candidates are surfaced — see §2.5 Phase 1, "Structural needs first.")
  2. Browse both libraries for candidates against those needs. patterns.md is read in full at build init; Timesaver candidates are loaded as PNGs via the multimodal Read tool. (See §0.6.1 for the worked example.)
  3. Pick the candidate that best matches the locked needs. Either path is a legitimate winner — the rationale ties back to the needs, not to a preference for one library.

Why both paths get equal weight: patterns.md is faster to build with for content that's genuinely card-shaped or column-shaped. Timesaver structures carry meaning the components can't — a hub-and-spoke says something about relationships, a house says something about dependencies. If you only consult patterns.md, you produce slides that look right but miss the structural metaphor. If you only consult Timesaver, you force shapes onto content that doesn't need them. Browse both, every time.

Bespoke metaphor is the third option for content that doesn't fit either library — see "Universal Closers & Metaphor Primitives" in metis-brand.md. This is the fallback, not a default; it requires an explicit rationale that neither library fits.

Path B assets

The catalog ships in this skill: references/timesaver_index.md — 260 rows with hand-written "Use when..." triggers.

PNG previews live on the shared drive:

G:\Shared drives\Knowledge Management\New Brand Assets\PPT Assets\timesaver_pngs\slide-{N}.png

Every Metis machine has the G:\ drive mapped, so the path resolves identically for everyone — no per-user setup, no rendering, no caching.

Requirements: Read access to G:\Shared drives\Knowledge Management\New Brand Assets\ (default for all Metis staff).

The thought-to-shape browse

  1. Read references/timesaver_index.md. Scan the "Use when..." column. Find rows that match the thought.
  2. Load 2-4 candidate previews via the multimodal Read tool from the shared-drive path above (slide-{N}.png for each candidate row).
  3. Pick the winner. Then write python-pptx code that reproduces the layout — using the brand tokens from metis-brand.md (colors, fonts, master, margins).

Examples of thought → shape:

ThoughtShapeCatalog ref
Three layers, each depending on the one belowHouse (foundation → body with pillars → roof)slide 179
Six things that reinforce each otherHoneycomb / hex flywheelslide 155
Three units forming a unified wholeTriangle conceptslide 160
Now → near → far progressionLinear process / chevron flowslide 114
One center radiating to many capabilitiesHub-and-spoke (e.g., McKinsey 7-S)slide 200
Branching decision logicDecision treeslide 130
Narrowing stages from broad to specificFunnelslide 167
Two states being comparedComparison chart or Before/Afterslide 175

If neither path fits the thought, build a bespoke metaphor from primitives (triangles, hexagons, chevrons, pillars). See metis-brand.md "Universal Closers & Metaphor Primitives."

0.6.1 Worked example — both paths considered

The browse described above is a sequence of concrete tool calls in the conversation, not an abstract recommendation. Below is what it looks like end-to-end for one slide. Reproduce this shape for every content slide.

Slide spec (generic):

"Build a content slide titled Three layers of platform capability. The slide describes a foundation layer, a middle services layer, and a top experience layer — each layer depends on the one below."

Step 1 — Articulate structural needs from the content.

Before surfacing any candidates, write the structural requirements. These are content-derived, not library-derived:

  • Three discrete layers, stacked.
  • Each layer depends on the layer below.
  • Foundation is widest / most fundamental; top is narrowest / most user-facing.

These are the locked criteria. The candidate that wins must match them.

Step 2 — Surface candidates from both libraries.

From patterns.md: a stacked-card layout (#9 Cards+Header, three rows) could plausibly fit. Component is in conversation context already (patterns.md was read at build init).

From timesaver_index.md (the "Concept slides — metaphors" section): candidates include:

  • slide-179 (House chart) — "layered architecture (foundation → body → roof)"
  • slide-159 (Pyramid concept) — "broad base narrowing to a peak"
  • slide-185 (Level diagram) — "discrete graduated levels"

Load the candidate PNGs via the multimodal Read tool:

Read("G:\Shared drives\Knowledge Management\New Brand Assets\PPT Assets\timesaver_pngs\slide-179.png")
Read("G:\Shared drives\Knowledge Management\New Brand Assets\PPT Assets\timesaver_pngs\slide-185.png")

(House and Level Diagram are the closest matches to the locked needs; Pyramid is a weaker match because the content doesn't imply narrowing.)

Step 3 — Pick against the locked needs.

slide-179 (House) carries all three structural needs: stacked layers, dependency (the body depends on the foundation, the roof depends on the body), and the foundation-widest visual logic.

slide-185 (Level Diagram) carries layers and graduated tiers, but the dependency relationship is implicit and weaker.

patterns.md #9 (Cards) carries layer enumeration but not dependency. The cards sit side by side or in a grid — they don't structurally show one depending on another.

Pick: timesaver slide-179 (House). Rationale ties back to locked needs: "slide-179 is the only candidate that carries layered + dependency + foundation-widest visual semantics. The other candidates require external annotation to communicate dependency, which the House metaphor does intrinsically."

Step 4 — Reproduce the layout.

Reproduce slide-179 in python-pptx using brand tokens from metis-brand.md. Don't freehand the layout from memory; the candidate PNG is in conversation context — refer to it for shape positions, hierarchy, label placement.


Anti-patterns — what this workflow done wrong looks like:

  • No PNG load. Citing timesaver slide-179 in the plan without ever calling the Read tool on the corresponding PNG. The citation is unverifiable and the build will be a freehand approximation, not a reproduction.
  • Single-library browse. Considering only Timesaver candidates and ignoring patterns.md, or vice versa. Both libraries get loaded at build init; both get evaluated against the locked needs.
  • Reverse-engineered needs. Articulating structural needs after the candidate is already chosen, so the needs conveniently match the pick. The Write of needs comes before the candidate Reads; the conversation log shows the order.
  • Generic rationale. "House looks better" or "this fits the brand" — the rationale must reference specific structural needs and explain why the pick carries them better than the alternative.

1. Editing Workflow

Use this workflow when an existing .pptx file is provided or referenced. This workflow preserves the template's layouts, themes, formatting, and brand identity.

1.1 Python Environment

Python is installed but NOT on the git bash PATH. Use the full path:

PYTHON="C:/Users/$USER/AppData/Local/Programs/Python/Python312/python.exe"

Required packages: python-pptx, defusedxml, lxml, Pillow, pywin32, markitdown Do NOT loop trying to install Python or add it to PATH. It is already installed.

All script paths below are relative to this skill's directory. Locate it with:

SKILL_DIRS=(
    "$HOME/.metis/skills/.agents/skills/tessl__metis-pptx"
    "$HOME/.metis/skills/.tessl/tiles/metis-strategy/metis-pptx"
    ".tessl/tiles/metis-strategy/metis-pptx"
)
for d in "${SKILL_DIRS[@]}"; do
    if [ -d "$d/scripts" ]; then SKILL_DIR="$d"; break; fi
done

1.2 Analyze the Existing Deck

Before making any changes, understand the deck:

# Visual overview — exports each slide as a PNG image
"$PYTHON" "$SKILL_DIR/scripts/visual_qa.py" input.pptx slide_images/

# Text content extraction
"$PYTHON" -m markitdown input.pptx

Review the exported slide images and extracted text to understand:

  • How many slides exist and their order
  • What layouts are used
  • Where content lives on each slide
  • The deck's visual style and brand

1.2.1 Slide-by-Slide Triage

After analyzing the deck, classify every slide into one of three categories before making any changes:

CategoryWhen to useAction
Keep & EditThe slide's visual layout matches the new content structure (same number of items, same hierarchy, similar text lengths)Edit text in place via XML
Duplicate & RebuildThe slide's layout/grid is right but the content structure differs significantly (different number of items, different hierarchy, much longer/shorter text)Duplicate the slide, strip content, rebuild using the layout's placeholders and shapes as a skeleton
New SlideNo existing slide has a layout that fits the new content, OR the source slide's visual structure is fundamentally incompatible (e.g., a manufacturing Gantt chart being reused for a strategic capability overview)Create a new slide from a layout using add_slide.py with a slideLayout, then build content using patterns from references/patterns.md with extracted brand tokens

A slide is NOT reusable when:

  • It has a specialized visual structure (timeline, Gantt, matrix, process flow) that doesn't map to the new content's logical structure
  • The source has N items but the new content has a significantly different count (e.g., 6 manufacturing stages vs. 3 strategic themes)
  • It contains positioned shapes (arrows, connectors, icons) whose placement depends on the original content's meaning
  • Replacing the text would require most items to be significantly longer or shorter than the originals, causing overflow or empty space

A slide IS reusable when:

  • It's a standard layout (title + bullets, title + 3-column, section divider)
  • The new content has the same number of items in the same visual hierarchy
  • Text lengths are roughly comparable (within ~30% character count)
  • The visual metaphor still applies (e.g., Start/Win/Stay chevrons work for both divisions)

Write out the triage as a table in your plan before starting any edits:

| Slide # | Current Content | New Content | Category | Rationale |
|---------|----------------|-------------|----------|-----------|
| 1 | PSG Title | CTD Title | Keep & Edit | Same layout, just text swap |
| 9 | Data & AI Timeline | Labeling Transformation | New Slide | Timeline axis doesn't apply; empty boxes |
| 15 | PSG Gantt Roadmap | CTD Roadmap | New Slide | Granular Gantt doesn't fit higher-level view |

1.3 Extract Brand Tokens (Non-Metis Decks)

If the deck is NOT Metis-branded, extract the client's brand tokens:

"$PYTHON" "$SKILL_DIR/scripts/extract_brand.py" input.pptx

This outputs a JSON dict with:

  • colors: primary fills, text colors, accents
  • fonts: title font, body font, caption font (with sizes)
  • content_area: left, top, right, bottom boundaries
  • layouts: all available slide layouts and which are used

Use these tokens when creating new slides so they match the client's style.

1.4 Unpack

Extract the .pptx for editing:

"$PYTHON" "$SKILL_DIR/scripts/unpack.py" input.pptx unpacked/

This extracts all XML files, pretty-prints them, and escapes smart quotes.

1.5 Structural Changes

Complete ALL structural changes before editing content.

Duplicate a slide:

"$PYTHON" "$SKILL_DIR/scripts/add_slide.py" unpacked/ slide2.xml
# Prints: Created slide5.xml from slide2.xml
# Prints: Add to presentation.xml <p:sldIdLst>: <p:sldId id="259" r:id="rId8"/>

Create a slide from a layout:

# See available layouts:
ls unpacked/ppt/slideLayouts/
"$PYTHON" "$SKILL_DIR/scripts/add_slide.py" unpacked/ slideLayout2.xml

Delete a slide: Remove its <p:sldId> from <p:sldIdLst> in unpacked/ppt/presentation.xml.

Reorder slides: Rearrange <p:sldId> elements in <p:sldIdLst>.

After adding slides, update presentation.xml by inserting the printed <p:sldId> element at the desired position in <p:sldIdLst>.

1.5.1 Safe Slide Deletion

Deleting slides requires cleanup beyond just removing the <p:sldId> entry. Follow this sequence:

  1. Remove the <p:sldId> element from <p:sldIdLst> in presentation.xml
  2. Delete the slide XML file (ppt/slides/slideN.xml)
  3. Delete the slide's .rels file (ppt/slides/_rels/slideN.xml.rels)
  4. Remove the relationship entry from ppt/_rels/presentation.xml.rels (the <Relationship> with the matching rId)
  5. Remove the Content-Type override from [Content_Types].xml (the <Override> for /ppt/slides/slideN.xml)
  6. Run clean.py to catch any remaining orphaned media, notes, or references

Never delete slides using python-pptx's internal API (drop_rel(), sldIdLst.remove(), etc.) — this leaves orphaned references that corrupt the file and make it unopenable in PowerPoint. Always delete via the unpacked XML approach above, then run clean.py before pack.py.

If you need to remove many slides and the XML approach is impractical, use PowerPoint COM to delete properly:

ppt = win32com.client.Dispatch('PowerPoint.Application')
pres = ppt.Presentations.Open(path, WithWindow=False)
for idx in sorted(indices_to_delete, reverse=True):
    pres.Slides(idx).Delete()
pres.Save()
pres.Close()
ppt.Quit()

COM handles all internal cleanup (relationships, content types, notes) automatically.

1.6 Edit Content

For each slide classified as "Keep & Edit" in triage (Section 1.2.1):

  1. Read the slide XML: unpacked/ppt/slides/slide{N}.xml
  2. Identify ALL content elements — text runs, images, charts
  3. Replace each element with final content

Use the Edit tool, not sed or Python scripts. The Edit tool forces specificity.

1.6.1 Content Authoring vs. Text Replacement

This is NOT a find-and-replace exercise. You are authoring new content that happens to live in an existing visual container. The distinction matters:

  • Text replacement (wrong): "Find 'PSG' and replace with 'CTD' everywhere" — this misses context, leaves orphaned metrics, and produces hybrid content where some values are from the source deck and others are new
  • Content authoring (right): Read each shape, understand what it communicates in the source deck, then write the equivalent new content from scratch using the target source materials

For every text shape you edit:

  1. Read the source text and understand its purpose (is it a metric? a capability description? a label?)
  2. Write the new content from the target source materials, not by modifying the source deck's text
  3. Verify the new text fits the container (similar character count, similar line count)
  4. Verify all quantitative values come from the target data, not leftover source numbers

1.6.2 Formatting Preservation

When replacing text in XML, preserve the original formatting by keeping the <a:rPr> (run properties) element intact and only changing the <a:t> (text) element. If a shape has multiple runs with different formatting (e.g., a bold red label followed by regular black description), maintain that run structure.

Common formatting failures to avoid:

  • Replacing a multi-run paragraph with a single run (loses inline formatting like bold labels)
  • Changing text in a bulleted list without preserving <a:buChar> or <a:buAutoNum> on each <a:pPr>
  • Writing longer text into a fixed-size shape without checking for overflow
  • Clearing a text frame and rebuilding it (loses paragraph-level formatting like spacing, alignment, indentation, bullet style)

When the new content has different structure than the old (e.g., 3 bullets to 5 bullets), you must add or remove <a:p> elements. Copy the <a:pPr> (paragraph properties) from an existing paragraph to maintain consistent bullet style, indentation, and spacing.

1.7 Adding New Slides to Client Decks

When you need to create new slides that match the client's style:

  1. Read references/patterns.md to pick the right grid pattern and component patterns
  2. Use the extracted brand tokens (from step 1.3) for colors, fonts, and spacing
  3. Build the slide using the client's coordinates and palette — NOT the Metis hardcoded values

For Metis-branded decks being edited, you may reference references/metis-brand.md for the code recipes.

1.7.1 Hybrid Workflow: Editing + Generation

Most real-world editing tasks are hybrid: some slides are edited in place, others need to be built from scratch. This is expected and correct — do not force every slide through the same workflow.

After completing triage (Section 1.2.1), you will typically have:

  • Keep & Edit slides — process via the XML editing workflow (Sections 1.4-1.6)
  • New Slides — process via a generation-like workflow but using the client's brand tokens instead of Metis brand constants

For New Slides in a client deck:

  1. Create the slide from a layout: "$PYTHON" "$SKILL_DIR/scripts/add_slide.py" unpacked/ slideLayoutN.xml
  2. Choose the right component pattern from references/patterns.md
  3. Build the slide content using extracted brand tokens (colors, fonts, spacing from Section 1.3)
  4. Write the content shapes into the new slide's XML using the Edit tool
  5. Insert the <p:sldId> at the correct position in presentation.xml

Key principle: A deck that mixes edited originals with well-crafted new slides (using the same brand tokens) will look more cohesive than a deck where every slide is force-fit via text replacement into layouts that don't match the content.

When building new slides for a client deck, adapt the python-pptx component recipes from references/metis-brand.md by substituting the client's brand tokens for the Metis constants:

  • Replace DARK_NAVY with the client's primary_fill color
  • Replace Calibri with the client's primary font
  • Replace Metis margins with the client's content_area boundaries

1.7.2 Build → Render → Inspect → Iterate → Inject (Surgical Single-Slide Editing)

Use this workflow when you need to add a small number of new slides to an existing deck without disturbing any prior slide. It isolates new construction in a sandbox file, forces visual review, and uses PowerPoint's own Slides.InsertFromFile for the final commit — which preserves the source master so brand framing carries over cleanly.

Step 1 — Build the new slides in a separate sandbox file.

  • Start the sandbox from master.pptx (so the brand frame is inherited).
  • Add only the new slides, picking shapes from the Timesaver library (see §0.6) or building bespoke metaphors from primitives.
  • Save the build script as a reproducible Python file (e.g., build_new_slides.py).

Step 2 — Render the new slides to PNG via PowerPoint COM.

import win32com.client
ppt = win32com.client.Dispatch("PowerPoint.Application")
ppt.Visible = 1
pres = ppt.Presentations.Open(SANDBOX_PATH, WithWindow=False)
for idx in NEW_SLIDE_INDICES:
    out = f"renders/slide-{idx}.png"
    pres.Slides(idx).Export(out, "PNG", 1920, 1080)
pres.Close()
ppt.Quit()

Step 3 — Inspect each PNG via the multimodal Read tool. Iterate.

  • Read each PNG. Look for overlap, overflow, low-contrast, alignment issues (see §3.4 checklist).
  • Fix the build script and re-render. The first render is almost never correct.
  • Do not skip this step. Visual review must happen before you touch the target deck.

Step 4 — Inject into the target deck via Slides.InsertFromFile.

import shutil, win32com.client

# Always back up the target first
shutil.copyfile(TARGET, TARGET + ".bak_preInsert.pptx")

ppt = win32com.client.Dispatch("PowerPoint.Application")
pres = ppt.Presentations.Open(TARGET, WithWindow=False)
# Slides.InsertFromFile(FileName, Index, SlideStart, SlideEnd)
#   Index = position AFTER which the new slides should appear
#   SlideStart..SlideEnd = source slide numbers (inclusive)
# Example: source slide 2 inserted after target position 5 → becomes new slide 6
pres.Slides.InsertFromFile(SANDBOX, 5, 2, 2)
pres.Save(); pres.Close(); ppt.Quit()

Why this works: InsertFromFile preserves the source master on the inserted slides. As long as the sandbox uses Metis master.pptx branding, the inserted slides land in the target with full Metis formatting — no XML rewriting, no risk of corrupting prior slides, no re-doing brand tokens.

Position math (the trap to avoid): after each insert the deck shifts. If you want final positions 6, 10, 11, the second InsertFromFile's Index value must be computed against the post-insert-1 deck, not the original. Always print slide titles before/after each insert to verify positions.

1.8 Formatting Rules for XML Editing

  • Bold all headers, subheadings, and inline labels: Use b="1" on <a:rPr>
  • Never use unicode bullets (•): Use proper list formatting with <a:buChar> or <a:buAutoNum>
  • Multi-item content: Create separate <a:p> elements for each item — never concatenate into one string
  • Smart quotes: When adding new text with quotes, use XML entities:
    • Left double quote: &#x201C;
    • Right double quote: &#x201D;
    • Left single quote: &#x2018;
    • Right single quote: &#x2019;
  • Whitespace: Use xml:space="preserve" on <a:t> with leading/trailing spaces

1.9 Template Adaptation Rules

  • When source content has fewer items than the template: remove excess elements entirely, don't just clear text
  • When replacing text with longer content: may overflow — test with visual QA
  • When replacing text with shorter content: usually safe
  • Template slots ≠ source items: If template has 4 items but you only need 3, delete the 4th group entirely

Overflow Decision Tree

Before committing a text replacement, compare the character count of old vs. new content:

New vs. Old LengthRiskAction
Within ~30%LowReplace and verify in QA
30-60% longerMediumReplace, but check the shape has wordWrap and adequate height. Consider abbreviating.
>60% longerHighDo NOT force-fit. Either abbreviate the content, or classify this slide as "New Slide" in triage and rebuild with a layout that fits.
Significantly shorterLowReplace, but remove any excess visual elements (extra bullet markers, connector lines) that now point at empty space

Never rely on PowerPoint's auto-shrink (<a:bodyPr fontScale="...">) to handle overflow. If the text doesn't fit at the original font size, the slide needs redesign, not font shrinking.

1.10 Clean + Pack

"$PYTHON" "$SKILL_DIR/scripts/clean.py" unpacked/
"$PYTHON" "$SKILL_DIR/scripts/pack.py" unpacked/ output.pptx --original input.pptx

clean.py removes orphaned slides, media, and relationships. pack.py validates, condenses XML, and repacks with auto-repair.

1.11 Visual QA

"$PYTHON" "$SKILL_DIR/scripts/visual_qa.py" output.pptx qa_images/

See Section 3 for the full QA process.


2. Generation Workflow

Use this workflow when building a new Metis-branded deck from scratch.

2.1 Asset Paths

AssetPath
Master template (blank deck with slide masters)G:\Shared drives\Knowledge Management\New Brand Assets\PowerPoint Templates\master.pptx
Firm overview slides (8 slides)G:\Shared drives\Knowledge Management\New Brand Assets\PowerPoint Templates\intro-slides.pptx
Icon LibraryG:\Shared drives\Knowledge Management\New Brand Assets\PowerPoint Templates\Icon_Lib.pptx
Logo — WhiteG:\Shared drives\Knowledge Management\New Brand Assets\Metis Strategy Logo\Metis Strategy White RGB logo.png
Logo — Black-MintG:\Shared drives\Knowledge Management\New Brand Assets\Metis Strategy Logo\Metis Strategy Black-Mint RGB Logo.png

2.2 Python Environment

Python is installed but NOT on the git bash PATH. Use the full path:

PYTHON="C:/Users/$USER/AppData/Local/Programs/Python/Python312/python.exe"
"$PYTHON" build_deck.py

Required package: python-pptx — if missing: "$PYTHON" -m pip install python-pptx Do NOT loop trying to install Python or add it to PATH. It is already installed.

2.3 Design System

Two co-equal design paths share the same brand system. Per slide, pick the path that fits the content (see §0.6 for routing rules):

  • Path A (component recipes): Read references/patterns.md for component selection. Read references/metis-brand.md for python-pptx code recipes.
  • Path B (Timesaver structures): Read references/timesaver_index.md for the "Use when..." catalog. Load PNG candidates from the shared drive (see §0.6).

Both paths share the brand constants below.

Key brand constants:

  • Colors: Dark Navy #20206E, Metis Blue #256BA2, Mint #3BDAC0, Dark Gray #4A4A4A, Light Gray #F2F2F2
  • Font: Calibri only. Title 28pt bold navy, body 14pt dark gray, caption 11pt blue.
  • Margins: Content area starts at (0.50", 1.10") and ends at (12.83", 6.80"). Slide is 13.33" x 7.50".

2.4 Layout Grids

Read references/patterns.md for the grid selection guide — which grid suits your content. Read references/metis-brand.md for exact Metis coordinates and code for each grid.

GridBest for
1. Full WidthExecutive summaries, narratives, key findings
2. Two ColumnComparisons, before/after, pros/cons
3. Sidebar + MainKPI callout + explanation
4. Three ColumnPhases, pillars, options
5. Title + VisualProcess flows, org charts, tables

2.5 Phased Build Workflow

Phase 1: Plan the Deck

1.0 Build init (mandatory, once per deck before slide planning)

Before any slide-by-slide planning, prime the conversation with both candidate libraries. This is the precondition that makes the per-slide browse in §0.6 meaningful — the agent can't compare candidates from two libraries it hasn't loaded.

  1. Read references/representatives.json. This file maps each Timesaver catalog section to 3–4 canonical exemplar slide-Ns. Load each listed PNG via the multimodal Read tool from G:\Shared drives\Knowledge Management\New Brand Assets\PPT Assets\timesaver_pngs\slide-{N}.png. Total: ~50 PNG loads. These provide visual awareness of every catalog section, not just the one the agent's first instinct points at.

  2. Read references/patterns.md in full. Components are in context alongside the Timesaver representatives.

After build init, both libraries are in conversation context. The per-slide pick (§0.6) becomes a comparison against locked structural needs, not a reach for one library by default.

Why build init is mandatory: the failure mode it prevents is content-type misclassification. If the agent decides "this is enumeration, only browse the Text-based section," it loads candidates only from one section and can't recognize when a slide actually fits a metaphor it hasn't seen. Loading representatives from every section eliminates that failure point.

Build init applies to single-slide and quick-build tasks too — don't scope it down. A common rationalization is "this is just one slide / a quick draft / an iteration on an existing deck, the full sweep is overkill." That reasoning is wrong, and naming it here so it can be recognized when the temptation appears: misclassification is a per-slide failure mode, not a per-deck one. A single-slide planner that loads only candidates from the section it thinks the slide belongs to has the same blind spot as a single-slide planner that skips the catalog entirely. Scope-down variants of this argument — "single-slide is different," "this is just a draft," "I'm iterating, full load is wasteful" — all share the same shape and should be recognized as the same shortcut. Single-slide planning pays the same build-init cost as multi-slide planning. By design.

1.1 Slide-by-slide outline

After build init, create the outline:

Slide 1: Cover (fixed) — "Client Name — Project Title"
Slide 2: Agenda (content, Grid 1) — 4 agenda items
Slide 3-12: Firm Overview (fixed, optional) — ask user if needed
Slide 13: Section Divider (fixed) — "Our Approach"
Slide 14: Three-Phase Process (content, Grid 4) — Discovery, Design, Deliver
...

For each content slide, the plan must include:

  • Structural needs (written first, before any candidate is surfaced — see "Structural needs first" below)
  • patterns.md candidate + corresponding component reference loaded (from the build-init full read)
  • timesaver candidate + corresponding PNG loaded via multimodal Read
  • Chosen Source — either path is legitimate
  • Why — rationale tying the pick back to the locked structural needs
1.2 Structural needs first (per content slide)

For each content slide, write the structural needs before surfacing candidates. This is the bias-fighting step: by committing to what the slide structurally requires before looking at what's available, the candidate selection has to defend itself against the locked criteria, not against the agent's preference for one library.

Format:

Slide content: <one-line summary of what the slide says>
Structural requirements (derived from content, not from libraries):
  1. <e.g., "show four parties around a center">
  2. <e.g., "imply bidirectional contribution">
  3. <e.g., "make the center smaller than the parties to signal stewardship">

Vague requirements ("clean, on-brand, professional") are not valid. The requirements must derive from the slide's actual content and structural relationships — things a reviewer can match against any candidate.

1.3 Both candidates with read evidence (per content slide)

For every content slide, the plan includes:

  • A patterns.md candidate (component number + brief reason it fits the locked needs)
  • A timesaver candidate (slide-N + brief reason it fits the locked needs, with the corresponding PNG loaded via Read)

Both candidates require corresponding Read tool calls earlier in the conversation. For Timesaver candidates that's the PNG; for patterns.md candidates that's the build-init full read of patterns.md (which already covers the component). A citation without read evidence is not valid.

Then pick the chosen Source and write the rationale — referencing the locked structural needs, not introducing new criteria at decision time.

1.4 Visual Variety Rule

Apply during planning:

  1. No-repeat rule: The primary component on slide N must differ from slide N-1 AND slide N-2. If three consecutive slides have the same content type (e.g., "key points"), use three different components from the rotation alternatives for that type (see Component Rotation Guide in patterns.md).
  2. Grid diversity: Across any 5 consecutive content slides, use at least 2 different grid layouts. A deck where every content slide uses the same grid is monotonous even if the components vary.
  3. Rhythm breakers: Every 3-4 content slides, insert one slide that uses a fundamentally different visual form — a pull quote (#36), a before/after (#20), a framework diagram (#31 or #32), a process visual (#22 or #24), or a Timesaver metaphor structure (e.g., House slide-179, Honeycomb slide-155, Decision Tree slide-130). These prevent the "wall of cards" effect.
  4. Write it in the outline: The slide plan MUST include all the columns described in §1.1 — Structural needs, both candidate columns, Chosen Source, Why. See the example table below:

Visual Variety Rule — apply during planning:

  1. No-repeat rule: The primary component on slide N must differ from slide N-1 AND slide N-2. If three consecutive slides have the same content type (e.g., "key points"), use three different components from the rotation alternatives for that type (see Component Rotation Guide in patterns.md).
  2. Grid diversity: Across any 5 consecutive content slides, use at least 2 different grid layouts. A deck where every content slide uses the same grid is monotonous even if the components vary.
  3. Rhythm breakers: Every 3-4 content slides, insert one slide that uses a fundamentally different visual form — a pull quote (#36), a before/after (#20), a framework diagram (#31 or #32), a process visual (#22 or #24), or a Timesaver metaphor structure (e.g., House slide-179, Honeycomb slide-155, Decision Tree slide-130). These prevent the "wall of cards" effect.
  4. Write it in the outline: The slide plan MUST include a Source column naming either a patterns.md component number or a timesaver slide-{N} reference for each content slide:
| # | Title                        | Type    | Structural needs                            | patterns.md cand.       | timesaver cand.             | Chosen                      | Why                                                  |
|---|------------------------------|---------|---------------------------------------------|-------------------------|-----------------------------|-----------------------------|------------------------------------------------------|
| 1 | Cover                        | fixed   | —                                           | —                       | —                           | —                           | —                                                    |
| 2 | Agenda                       | content | 4 sequential topics, equal weight            | #7 Callout              | slide-23 (Four categories)  | #7 Callout                  | enumeration; no metaphor adds value                  |
| 3 | The Opportunity              | content | one bold claim + supporting context          | #36 Pull Quote          | slide-22 (Statements)       | #36 Pull Quote              | quote primacy fits hero framing better than 3-up     |
| 4 | Market Landscape             | content | 3 segments, equal weight, comparable         | #9 Cards+Header         | slide-23 (Four categories)  | #9 Cards+Header             | enumerative; comparison is implicit                  |
| 5 | Strategic Pillars            | content | foundation → body → roof; layered dependency | #9 Cards+Header (3-row) | slide-179 (House)           | timesaver slide-179 (House) | dependency relationship needs metaphor               |
| 6 | Transformation Roadmap       | content | 5-step linear progression                    | #22 Process             | slide-114 (Linear Process)  | #22 Process                 | both fit; #22 is faster build, picks tied            |
| 7 | Capability Ecosystem         | content | 6 reinforcing pieces around a center         | #9 Cards+Header         | slide-155 (Hex flywheel)    | timesaver slide-155 (Hex)   | reinforcement needs the radial structure             |
| 8 | Closing / Call to Action     | content | single mantra, hero scale                    | #36 Pull Quote          | slide-32 (Quote + Comm.)    | #36 Pull Quote              | single sentence beats elaborated quote               |

The plan must include both candidate columns for every content slide — a patterns.md candidate AND a timesaver candidate — even when the chosen pick is obvious. Filling in both columns forces consideration of both libraries before the pick is made. The "Why" cell ties the choice back to the "Structural needs" cell.

Firm overview is optional. Ask the user: "Should I include the Metis firm overview slides?"

Phase 2: Write the Build Script

Create a single Python script (build_deck.py). Critical rules:

  • Always start from master.pptx — never open intro-slides.pptx directly as the base.
  • Use '1_Title Only' layout for content slides — gives green arrow, logo, footer, page number.
  • Never use 'Blank' for content slides — it has none of the brand elements.
  • Use 'Section Divider' layout for dividers — navy background is built in.
  • Set titles via placeholder (idx=0), not add_textbox().
  • Copy firm overview slides from intro-slides.pptx using the copy_slide_from() helper.
  • Deduplicate the zip before saving.

See references/metis-brand.md for the full boilerplate code including:

  • get_layout() helper
  • add_content_slide() helper
  • add_section_divider() helper
  • copy_slide_from() helper
  • save_clean() helper

Phase 3: Build Content Slides

For each content slide, follow the path picked in Phase 1:

Path A (component recipe):

  1. Add a content slide: slide = add_content_slide("Title", "Subtitle")
  2. Choose components from references/patterns.md — every Path-A content slide MUST use at least one component. Plain text on white is never acceptable.
  3. Get the code recipe from references/metis-brand.md and call the component functions.
  4. Add content shapes below the title area (starting at y=1.10").

Path B (Timesaver structure):

  1. Add a content slide: slide = add_content_slide("Title", "Subtitle")
  2. Read the chosen Timesaver PNG from G:\Shared drives\Knowledge Management\New Brand Assets\PPT Assets\timesaver_pngs\slide-{N}.png via the multimodal Read tool.
  3. Reproduce the layout in python-pptx — shape positions, hierarchy, label placement — using brand tokens from references/metis-brand.md (colors, fonts, margins). Do not freehand colors or fonts.
  4. Add content shapes below the title area (starting at y=1.10").
  5. Verify visual variety: Before moving to the next slide, check:
    • Is the primary component different from the previous slide's primary component?
    • Has this exact grid+component combination appeared on any of the last 3 slides?
    • If either check fails, swap in an alternative component from the Component Rotation Guide in patterns.md.

Every text element must have real content. No placeholder text, no "Lorem ipsum."

Phase 4: Polish and Save

Before saving, verify:

  • Every slide has a title
  • No shapes contain placeholder text
  • All fonts are Calibri
  • All colors match the brand palette
  • Content is within margin bounds (0.50" to 12.83" horizontal, 1.10" to 6.80" vertical)

2.6 Deck Structure Guidelines

Proposals / BD Decks:

  1. Cover
  2. Firm Overview (optional — ask user)
  3. Our Understanding of Your Challenge (Grid 1)
  4. Our Approach (Grid 4 or Grid 5)
  5. Our Team (Grid 4)
  6. Investment (Grid 5 with table)
  7. Next Steps / Closing

In-Project Deliverables:

  1. Cover
  2. Agenda (Grid 1)
  3. Section Divider + Content slides (repeat per section)
  4. Key Findings / Recommendations (Grid 1 or Grid 2)
  5. Next Steps
  6. Appendix (Firm Overview here if included)

2.7 Common Patterns

Bullet list with accent markers:

bullets = ["Finding one", "Finding two", "Finding three"]
y = 1.10
for b in bullets:
    marker = slide.shapes.add_shape(MSO_SHAPE.OVAL, Inches(0.50), Inches(y + 0.05), Inches(0.12), Inches(0.12))
    marker.fill.solid()
    marker.fill.fore_color.rgb = MINT
    marker.line.fill.background()
    add_body(slide, b, 0.75, y, 12.08, 0.35)
    y += 0.45

Highlighted callout box:

box = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(0.50), Inches(y), Inches(12.33), Inches(1.50))
box.fill.solid()
box.fill.fore_color.rgb = LIGHT_GRAY
box.line.fill.background()
bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(0.50), Inches(y), Inches(0.06), Inches(1.50))
bar.fill.solid()
bar.fill.fore_color.rgb = MINT
bar.line.fill.background()

Section divider: Use the 'Section Divider' layout — never draw navy rectangles manually.

divider = prs.slides.add_slide(get_layout('Section Divider'))
for ph in divider.placeholders:
    if ph.placeholder_format.idx == 0:
        ph.text = "Section Title"

3. Visual QA (Both Modes)

Assume there are problems. Your job is to find them.

3.1 Export Slides as Images

"$PYTHON" "$SKILL_DIR/scripts/visual_qa.py" output.pptx qa_images/

This uses PowerPoint COM automation to render each slide as a high-fidelity PNG.

3.2 Thumbnail Grid

"$PYTHON" "$SKILL_DIR/scripts/thumbnail.py" output.pptx

Creates a grid overview of all slides for quick visual inspection.

3.3 Content QA

"$PYTHON" -m markitdown output.pptx

Check for missing content, typos, wrong order.

Check for leftover placeholder text:

"$PYTHON" -m markitdown output.pptx | grep -iE "\bx{3,}\b|lorem|ipsum|\bTODO|\[insert"

3.4 Visual QA Checklist

When inspecting slide images, look for:

  • Overlapping elements (text through shapes, lines through words)
  • Text overflow or cut off at edges/box boundaries
  • Elements too close (< 0.3" gaps) or sections nearly touching
  • Uneven gaps (large empty area in one place, cramped in another)
  • Insufficient margin from slide edges (< 0.5")
  • Columns or similar elements not aligned consistently
  • Low-contrast text (light gray on cream, dark on dark)
  • Text boxes too narrow causing excessive wrapping
  • Leftover placeholder content
  • Leftover source content: Any text, labels, metrics, or brand names from the original deck that weren't updated
  • Hybrid metrics: Numbers or KPIs that mix source and target data (e.g., a new revenue figure next to a growth multiplier from the original deck)
  • Empty containers: Shapes, boxes, or pill elements that had content in the source but are now empty or contain generic labels
  • Mismatched structure: Visual elements (timelines, arrows, connectors) whose spatial arrangement implies a relationship that doesn't exist in the new content
  • Formatting inconsistency: Slides where bullet style, text color, or font size varies from the rest of the deck (common when some slides are edited and others rebuilt)

3.5 Verification Loop

  1. Generate/edit the deck
  2. Export slides as images
  3. Inspect every slide — list issues found
  4. Fix issues
  5. Re-export affected slides — re-inspect
  6. Repeat until a full pass reveals no new issues

Do not declare success until you've completed at least one fix-and-verify cycle.

Workspace
metis-strategy
Visibility
Public
Created
Last updated
Publish Source
CLI
Badge
metis-strategy/metis-pptx badge