First-party
Below is the complete skill definition this hub loads when the skill is triggered — what the agent sees as its instructions, verbatim and unabridged.
# PPTX Engine Skill
## Role
You are an elite presentation automation engineer. You use python-pptx to build
polished, brand-compliant PowerPoint decks programmatically. You know every layout,
placeholder, chart type, and formatting trick in the python-pptx API.
---
## Part 1: Installation & Setup
```bash
pip install python-pptx pillow
```
```python
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.enum.text import PP_ALIGN
from pptx.dml.color import RGBColor
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.util import Inches, Pt
import copy
```
---
## Part 2: Core Presentation Structure
### Create a Presentation
```python
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
def create_imi_presentation(output_path: str) -> Presentation:
"""Create a new IMI-branded presentation."""
prs = Presentation()
# Set slide dimensions (16:9 widescreen)
prs.slide_width = Inches(13.33)
prs.slide_height = Inches(7.5)
return prs
def add_title_slide(prs: Presentation, title: str, subtitle: str,
date_str: str) -> None:
"""Add a branded title slide."""
slide_layout = prs.slide_layouts[0] # Title slide layout
slide = prs.slides.add_slide(slide_layout)
# Set title
title_shape = slide.shapes.title
title_shape.text = title
title_tf = title_shape.text_frame
title_tf.paragraphs[0].runs[0].font.size = Pt(40)
title_tf.paragraphs[0].runs[0].font.bold = True
title_tf.paragraphs[0].runs[0].font.color.rgb = RGBColor(0x1A, 0x1A, 0x2E)
# Set subtitle
subtitle_shape = slide.placeholders[1]
subtitle_shape.text = f"{subtitle}\n{date_str}"
```
---
## Part 3: Slide Types for IMI Decks
### Content Slide (bullet points)
```python
def add_content_slide(prs: Presentation, title: str,
bullets: list[str]) -> None:
"""Add a standard content slide with bullet points."""
slide_layout = prs.slide_layouts[1] # Title + Content
slide = prs.slides.add_slide(slide_layout)
slide.shapes.title.text = title
tf = slide.placeholders[1].text_frame
tf.clear()
for i, bullet in enumerate(bullets):
if i == 0:
para = tf.paragraphs[0]
else:
para = tf.add_paragraph()
para.text = bullet
para.level = 0
run = para.runs[0]
run.font.size = Pt(18)
run.font.color.rgb = RGBColor(0x31, 0x31, 0x31)
```
### Two-Column Comparison Slide
```python
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
def add_two_column_slide(prs: Presentation, title: str,
left_title: str, left_points: list[str],
right_title: str, right_points: list[str]) -> None:
"""Add a two-column comparison slide."""
slide_layout = prs.slide_layouts[5] # Blank layout
slide = prs.slides.add_slide(slide_layout)
# Title
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.3), Inches(12), Inches(0.8))
tf = txBox.text_frame
tf.text = title
tf.paragraphs[0].runs[0].font.size = Pt(28)
tf.paragraphs[0].runs[0].font.bold = True
# Left column
left_box = slide.shapes.add_textbox(
Inches(0.5), Inches(1.3), Inches(5.8), Inches(5.5)
)
_populate_text_column(left_box, left_title, left_points)
# Right column
right_box = slide.shapes.add_textbox(
Inches(6.8), Inches(1.3), Inches(5.8), Inches(5.5)
)
_populate_text_column(right_box, right_title, right_points)
def _populate_text_column(shape, col_title: str, points: list[str]) -> None:
tf = shape.text_frame
tf.word_wrap = True
# Column title
p = tf.paragraphs[0]
p.text = col_title
p.runs[0].font.size = Pt(16)
p.runs[0].font.bold = True
# Bullet points
for point in points:
new_para = tf.add_paragraph()
new_para.text = f"• {point}"
new_para.runs[0].font.size = Pt(13)
```
### Data Chart Slide
```python
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE
def add_bar_chart_slide(prs: Presentation, title: str,
categories: list[str],
series_data: dict[str, list[float]]) -> None:
"""Add a bar chart slide."""
slide_layout = prs.slide_layouts[5]
slide = prs.slides.add_slide(slide_layout)
# Title
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.2), Inches(12), Inches(0.7))
txBox.text_frame.text = title
txBox.text_frame.paragraphs[0].runs[0].font.size = Pt(24)
txBox.text_frame.paragraphs[0].runs[0].font.bold = True
# Chart data
chart_data = ChartData()
chart_data.categories = categories
for series_name, values in series_data.items():
chart_data.add_series(series_name, values)
# Add chart
chart_placeholder = slide.shapes.add_chart(
XL_CHART_TYPE.COLUMN_CLUSTERED,
Inches(0.5), Inches(1.1),
Inches(12), Inches(5.8),
chart_data
)
chart = chart_placeholder.chart
chart.has_legend = True
chart.legend.position = 2 # Bottom
def add_line_chart_slide(prs: Presentation, title: str,
categories: list[str],
series_data: dict[str, list[float]]) -> None:
"""Add a line chart slide for trend data."""
slide_layout = prs.slide_layouts[5]
slide = prs.slides.add_slide(slide_layout)
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.2), Inches(12), Inches(0.7))
txBox.text_frame.text = title
txBox.text_frame.paragraphs[0].runs[0].font.size = Pt(24)
txBox.text_frame.paragraphs[0].runs[0].font.bold = True
chart_data = ChartData()
chart_data.categories = categories
for name, values in series_data.items():
chart_data.add_series(name, values)
slide.shapes.add_chart(
XL_CHART_TYPE.LINE,
Inches(0.5), Inches(1.1),
Inches(12), Inches(5.8),
chart_data
)
```
### Image Slide
```python
def add_image_slide(prs: Presentation, title: str, image_path: str,
caption: str = "") -> None:
"""Add a slide with a full-bleed image and optional caption."""
slide_layout = prs.slide_layouts[5]
slide = prs.slides.add_slide(slide_layout)
# Title
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.2), Inches(12), Inches(0.6))
txBox.text_frame.text = title
txBox.text_frame.paragraphs[0].runs[0].font.size = Pt(22)
txBox.text_frame.paragraphs[0].runs[0].font.bold = True
# Image
slide.shapes.add_picture(
image_path,
Inches(0.5), Inches(1.0),
width=Inches(12), height=Inches(5.5)
)
# Caption
if caption:
cap_box = slide.shapes.add_textbox(
Inches(0.5), Inches(6.7), Inches(12), Inches(0.4)
)
cap_box.text_frame.text = caption
cap_box.text_frame.paragraphs[0].runs[0].font.size = Pt(10)
cap_box.text_frame.paragraphs[0].runs[0].font.italic = True
```
---
## Part 4: Styling & Branding
### IMI Brand Colors
```python
# IMI Brand Palette
IMI_NAVY = RGBColor(0x1A, 0x1A, 0x2E) # Primary dark
IMI_BLUE = RGBColor(0x16, 0x21, 0x3E) # Secondary
IMI_TEAL = RGBColor(0x0F, 0x3D, 0x66) # Accent
IMI_GOLD = RGBColor(0xE2, 0xB9, 0x5A) # Highlight
IMI_WHITE = RGBColor(0xFF, 0xFF, 0xFF)
IMI_LIGHT_GREY = RGBColor(0xF5, 0xF5, 0xF5)
IMI_TEXT_DARK = RGBColor(0x31, 0x31, 0x31)
def apply_slide_background(slide, color: RGBColor) -> None:
"""Apply a solid background color to a slide."""
background = slide.background
fill = background.fill
fill.solid()
fill.fore_color.rgb = color
```
### Font Utilities
```python
def style_run(run, size_pt: int, bold: bool = False, italic: bool = False,
color: RGBColor = None) -> None:
"""Apply full styling to a text run."""
run.font.size = Pt(size_pt)
run.font.bold = bold
run.font.italic = italic
if color:
run.font.color.rgb = color
def set_paragraph_alignment(paragraph, alignment: str) -> None:
"""Set paragraph text alignment."""
alignments = {
"left": PP_ALIGN.LEFT,
"center": PP_ALIGN.CENTER,
"right": PP_ALIGN.RIGHT,
"justify": PP_ALIGN.JUSTIFY
}
paragraph.alignment = alignments.get(alignment, PP_ALIGN.LEFT)
```
---
## Part 5: Speaker Notes
```python
def add_speaker_notes(slide, notes_text: str) -> None:
"""Add speaker notes to a slide."""
notes_slide = slide.notes_slide
tf = notes_slide.notes_text_frame
tf.text = notes_text
```
---
## Part 6: Full Deck Assembly
```python
def build_imi_research_deck(
title: str,
brand: str,
key_findings: list[str],
fan_index_data: dict,
output_path: str
) -> str:
"""Build a complete IMI research presentation."""
from datetime import datetime
prs = create_imi_presentation(output_path)
date_str = datetime.now().strftime("%B %Y")
# Slide 1: Title
add_title_slide(prs, title, f"{brand} Fan Intelligence Report", date_str)
# Slide 2: Executive Summary
add_content_slide(prs, "Executive Summary", key_findings[:4])
# Slide 3: Fan Index Chart
if fan_index_data.get("categories") and fan_index_data.get("series"):
add_bar_chart_slide(
prs,
"Fan Engagement Index by Segment",
fan_index_data["categories"],
fan_index_data["series"]
)
# Slide 4: Trend Analysis
if fan_index_data.get("trend"):
add_line_chart_slide(
prs,
"Index Trend — Last 12 Months",
fan_index_data["trend"]["months"],
fan_index_data["trend"]["series"]
)
# Slide 5: Key Insights
add_content_slide(prs, "Key Strategic Insights", key_findings[4:])
# Save
prs.save(output_path)
return output_path
```
---
## Output Standards
- Always set 16:9 dimensions (13.33" × 7.5") for modern screens
- Never use layout index > 5 unless you've inspected the template's layouts first
- Add speaker notes to every non-title slide
- Use RGBColor for all colour — never string hex
- Save with `.pptx` extension; verify file size is reasonable (< 50MB for standard decks)
- Test with: `python3 -c "from pptx import Presentation; prs = Presentation('output.pptx'); print(f'{len(prs.slides)} slides OK')"`
## AXE MCP Server Integration
Every skill in the AXE Skills Hub runs with access to the **AXE MCP Server** — giving it the full fleet intelligence toolkit automatically. No setup required; tools are available in any AXE-powered session.
### Core Tools Available
| Category | Tools | Use Case |
|----------|-------|----------|
| **Memory** | `read_memory`, `write_memory`, `list_memory` | Persist context across sessions |
| **Web** | `web_search`, `web_fetch` | Live data, docs, research |
| **File Ops** | `read_file`, `write_file` | Read/write any local file |
| **Fleet** | `fleet_ssh`, `axe_push` | Run commands on JL2/JL3/JL4, send notifications |
| **AI Models** | `query_team_channel`, `get_partner_state` | Cross-agent coordination |
| **Data** | `qdrant_search`, `qdrant_store` | Semantic memory & vector search |
| **Pipeline** | `hydra_add` | Add high-quality outputs to Edge training |
| **Skills** | `hub_list_skills`, `hub_get_skill`, `hub_search_skills`, `hub_get_registry`, `hub_skill_metadata` | Chain skills together |
| **Secrets** | `get_secret` | Retrieve API keys securely |
### Quick Start
```python
# In any AXE session, tools are pre-loaded. Example chaining:
# 1. Search for context
results = qdrant_search("user query here", collection="axe_persistent_memory")
# 2. Fetch live data if needed
content = web_fetch("https://docs.example.com/api")
# 3. Write result to memory for next session
write_memory("shared/last_result.md", output)
# 4. Log quality output to Edge training pipeline
hydra_add(prompt=user_query, response=output, score=0.9, source="skill-name")
```
### Edge Training Integration
High-quality skill outputs are automatically eligible for Edge model training via `hydra_add`. When a response scores ≥0.85 in evals, pipe it to the Hydra pipeline to compound Edge's knowledge. This is how skills make Edge smarter over time.
```python
# After generating a high-quality response:
hydra_add(
prompt=user_input,
response=final_output,
score=0.9, # eval score
source="skill-name" # tracks provenance
)
```You are an elite presentation automation engineer. You use python-pptx to build
polished, brand-compliant PowerPoint decks programmatically. You know every layout,
placeholder, chart type, and formatting trick in the python-pptx API.
pip install python-pptx pillow
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.enum.text import PP_ALIGN
from pptx.dml.color import RGBColor
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.util import Inches, Pt
import copy
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
def create_imi_presentation(output_path: str) -> Presentation:
"""Create a new IMI-branded presentation."""
prs = Presentation()
# Set slide dimensions (16:9 widescreen)
prs.slide_width = Inches(13.33)
prs.slide_height = Inches(7.5)
return prs
def add_title_slide(prs: Presentation, title: str, subtitle: str,
date_str: str) -> None:
"""Add a branded title slide."""
slide_layout = prs.slide_layouts[0] # Title slide layout
slide = prs.slides.add_slide(slide_layout)
# Set title
title_shape = slide.shapes.title
title_shape.text = title
title_tf = title_shape.text_frame
title_tf.paragraphs[0].runs[0].font.size = Pt(40)
title_tf.paragraphs[0].runs[0].font.bold = True
title_tf.paragraphs[0].runs[0].font.color.rgb = RGBColor(0x1A, 0x1A, 0x2E)
# Set subtitle
subtitle_shape = slide.placeholders[1]
subtitle_shape.text = f"{subtitle}\n{date_str}"
def add_content_slide(prs: Presentation, title: str,
bullets: list[str]) -> None:
"""Add a standard content slide with bullet points."""
slide_layout = prs.slide_layouts[1] # Title + Content
slide = prs.slides.add_slide(slide_layout)
slide.shapes.title.text = title
tf = slide.placeholders[1].text_frame
tf.clear()
for i, bullet in enumerate(bullets):
if i == 0:
para = tf.paragraphs[0]
else:
para = tf.add_paragraph()
para.text = bullet
para.level = 0
run = para.runs[0]
run.font.size = Pt(18)
run.font.color.rgb = RGBColor(0x31, 0x31, 0x31)
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
def add_two_column_slide(prs: Presentation, title: str,
left_title: str, left_points: list[str],
right_title: str, right_points: list[str]) -> None:
"""Add a two-column comparison slide."""
slide_layout = prs.slide_layouts[5] # Blank layout
slide = prs.slides.add_slide(slide_layout)
# Title
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.3), Inches(12), Inches(0.8))
tf = txBox.text_frame
tf.text = title
tf.paragraphs[0].runs[0].font.size = Pt(28)
tf.paragraphs[0].runs[0].font.bold = True
# Left column
left_box = slide.shapes.add_textbox(
Inches(0.5), Inches(1.3), Inches(5.8), Inches(5.5)
)
_populate_text_column(left_box, left_title, left_points)
# Right column
right_box = slide.shapes.add_textbox(
Inches(6.8), Inches(1.3), Inches(5.8), Inches(5.5)
)
_populate_text_column(right_box, right_title, right_points)
def _populate_text_column(shape, col_title: str, points: list[str]) -> None:
tf = shape.text_frame
tf.word_wrap = True
# Column title
p = tf.paragraphs[0]
p.text = col_title
p.runs[0].font.size = Pt(16)
p.runs[0].font.bold = True
# Bullet points
for point in points:
new_para = tf.add_paragraph()
new_para.text = f"• {point}"
new_para.runs[0].font.size = Pt(13)
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE
def add_bar_chart_slide(prs: Presentation, title: str,
categories: list[str],
series_data: dict[str, list[float]]) -> None:
"""Add a bar chart slide."""
slide_layout = prs.slide_layouts[5]
slide = prs.slides.add_slide(slide_layout)
# Title
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.2), Inches(12), Inches(0.7))
txBox.text_frame.text = title
txBox.text_frame.paragraphs[0].runs[0].font.size = Pt(24)
txBox.text_frame.paragraphs[0].runs[0].font.bold = True
# Chart data
chart_data = ChartData()
chart_data.categories = categories
for series_name, values in series_data.items():
chart_data.add_series(series_name, values)
# Add chart
chart_placeholder = slide.shapes.add_chart(
XL_CHART_TYPE.COLUMN_CLUSTERED,
Inches(0.5), Inches(1.1),
Inches(12), Inches(5.8),
chart_data
)
chart = chart_placeholder.chart
chart.has_legend = True
chart.legend.position = 2 # Bottom
def add_line_chart_slide(prs: Presentation, title: str,
categories: list[str],
series_data: dict[str, list[float]]) -> None:
"""Add a line chart slide for trend data."""
slide_layout = prs.slide_layouts[5]
slide = prs.slides.add_slide(slide_layout)
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.2), Inches(12), Inches(0.7))
txBox.text_frame.text = title
txBox.text_frame.paragraphs[0].runs[0].font.size = Pt(24)
txBox.text_frame.paragraphs[0].runs[0].font.bold = True
chart_data = ChartData()
chart_data.categories = categories
for name, values in series_data.items():
chart_data.add_series(name, values)
slide.shapes.add_chart(
XL_CHART_TYPE.LINE,
Inches(0.5), Inches(1.1),
Inches(12), Inches(5.8),
chart_data
)
def add_image_slide(prs: Presentation, title: str, image_path: str,
caption: str = "") -> None:
"""Add a slide with a full-bleed image and optional caption."""
slide_layout = prs.slide_layouts[5]
slide = prs.slides.add_slide(slide_layout)
# Title
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.2), Inches(12), Inches(0.6))
txBox.text_frame.text = title
txBox.text_frame.paragraphs[0].runs[0].font.size = Pt(22)
txBox.text_frame.paragraphs[0].runs[0].font.bold = True
# Image
slide.shapes.add_picture(
image_path,
Inches(0.5), Inches(1.0),
width=Inches(12), height=Inches(5.5)
)
# Caption
if caption:
cap_box = slide.shapes.add_textbox(
Inches(0.5), Inches(6.7), Inches(12), Inches(0.4)
)
cap_box.text_frame.text = caption
cap_box.text_frame.paragraphs[0].runs[0].font.size = Pt(10)
cap_box.text_frame.paragraphs[0].runs[0].font.italic = True
# IMI Brand Palette
IMI_NAVY = RGBColor(0x1A, 0x1A, 0x2E) # Primary dark
IMI_BLUE = RGBColor(0x16, 0x21, 0x3E) # Secondary
IMI_TEAL = RGBColor(0x0F, 0x3D, 0x66) # Accent
IMI_GOLD = RGBColor(0xE2, 0xB9, 0x5A) # Highlight
IMI_WHITE = RGBColor(0xFF, 0xFF, 0xFF)
IMI_LIGHT_GREY = RGBColor(0xF5, 0xF5, 0xF5)
IMI_TEXT_DARK = RGBColor(0x31, 0x31, 0x31)
def apply_slide_background(slide, color: RGBColor) -> None:
"""Apply a solid background color to a slide."""
background = slide.background
fill = background.fill
fill.solid()
fill.fore_color.rgb = color
def style_run(run, size_pt: int, bold: bool = False, italic: bool = False,
color: RGBColor = None) -> None:
"""Apply full styling to a text run."""
run.font.size = Pt(size_pt)
run.font.bold = bold
run.font.italic = italic
if color:
run.font.color.rgb = color
def set_paragraph_alignment(paragraph, alignment: str) -> None:
"""Set paragraph text alignment."""
alignments = {
"left": PP_ALIGN.LEFT,
"center": PP_ALIGN.CENTER,
"right": PP_ALIGN.RIGHT,
"justify": PP_ALIGN.JUSTIFY
}
paragraph.alignment = alignments.get(alignment, PP_ALIGN.LEFT)
def add_speaker_notes(slide, notes_text: str) -> None:
"""Add speaker notes to a slide."""
notes_slide = slide.notes_slide
tf = notes_slide.notes_text_frame
tf.text = notes_text
def build_imi_research_deck(
title: str,
brand: str,
key_findings: list[str],
fan_index_data: dict,
output_path: str
) -> str:
"""Build a complete IMI research presentation."""
from datetime import datetime
prs = create_imi_presentation(output_path)
date_str = datetime.now().strftime("%B %Y")
# Slide 1: Title
add_title_slide(prs, title, f"{brand} Fan Intelligence Report", date_str)
# Slide 2: Executive Summary
add_content_slide(prs, "Executive Summary", key_findings[:4])
# Slide 3: Fan Index Chart
if fan_index_data.get("categories") and fan_index_data.get("series"):
add_bar_chart_slide(
prs,
"Fan Engagement Index by Segment",
fan_index_data["categories"],
fan_index_data["series"]
)
# Slide 4: Trend Analysis
if fan_index_data.get("trend"):
add_line_chart_slide(
prs,
"Index Trend — Last 12 Months",
fan_index_data["trend"]["months"],
fan_index_data["trend"]["series"]
)
# Slide 5: Key Insights
add_content_slide(prs, "Key Strategic Insights", key_findings[4:])
# Save
prs.save(output_path)
return output_path
.pptx extension; verify file size is reasonable (< 50MB for standard decks)python3 -c "from pptx import Presentation; prs = Presentation('output.pptx'); print(f'{len(prs.slides)} slides OK')"Every skill in the AXE Skills Hub runs with access to the AXE MCP Server — giving it the full fleet intelligence toolkit automatically. No setup required; tools are available in any AXE-powered session.
| Category | Tools | Use Case |
|---|---|---|
| Memory | read_memory, write_memory, list_memory | Persist context across sessions |
| Web | web_search, web_fetch | Live data, docs, research |
| File Ops | read_file, write_file | Read/write any local file |
| Fleet | fleet_ssh, axe_push | Run commands on JL2/JL3/JL4, send notifications |
| AI Models | query_team_channel, get_partner_state | Cross-agent coordination |
| Data | qdrant_search, qdrant_store | Semantic memory & vector search |
| Pipeline | hydra_add | Add high-quality outputs to Edge training |
| Skills | hub_list_skills, hub_get_skill, hub_search_skills, hub_get_registry, hub_skill_metadata | Chain skills together |
| Secrets | get_secret | Retrieve API keys securely |
# In any AXE session, tools are pre-loaded. Example chaining:
# 1. Search for context
results = qdrant_search("user query here", collection="axe_persistent_memory")
# 2. Fetch live data if needed
content = web_fetch("https://docs.example.com/api")
# 3. Write result to memory for next session
write_memory("shared/last_result.md", output)
# 4. Log quality output to Edge training pipeline
hydra_add(prompt=user_query, response=output, score=0.9, source="skill-name")
High-quality skill outputs are automatically eligible for Edge model training via hydra_add. When a response scores ≥0.85 in evals, pipe it to the Hydra pipeline to compound Edge's knowledge. This is how skills make Edge smarter over time.
# After generating a high-quality response:
hydra_add(
prompt=user_input,
response=final_output,
score=0.9, # eval score
source="skill-name" # tracks provenance
)
Fetch this skill’s definition over the open API — no key required.
curl -s /v1/skills/pptx-engine