deck
npx skills add https://github.com/octavehq/lfgtm --skill deck
Agent 安装分布
Skill 文档
/octave:deck – Octave-Powered Deck Builder
Build compelling, self-contained HTML presentations powered by your Octave GTM knowledge base. Unlike generic slide builders, this skill leverages your library’s personas, competitors, playbooks, proof points, and real conversation data to research, structure, and generate presentations grounded in your actual go-to-market intelligence.
HTML presentation engine inspired by frontend-slides by Zara Zhang (MIT license).
Usage
/octave:deck [topic or file] [--for <purpose>] [--audience <target>] [--style <preset>]
Examples
/octave:deck "pitch for Acme Corp" # Customer pitch, Octave researches Acme
/octave:deck "Q1 QBR for enterprise segment" # QBR with real pipeline data
/octave:deck --for competitive "vs Gong" # Competitive presentation
/octave:deck "product launch GTM plan" # Internal strategy deck
/octave:deck ~/Downloads/existing-deck.pptx # Convert PPTX to HTML
/octave:deck "demo day pitch" --style octave-brand # Specific style preset
/octave:deck "sales kickoff enablement" --audience "new AEs" # Audience-targeted
Instructions
When the user runs /octave:deck:
Step 1: Understand the Purpose & Goal
If not provided via flags, ask the user interactively using AskUserQuestion:
Purpose â “What kind of deck is this?”
What kind of deck are you building?
1. Customer pitch / pre-demo deck
2. Customer QBR / business review
3. Internal strategy / planning
4. Conference talk / keynote
5. Product launch / GTM plan
6. Competitive battlecard presentation
7. Sales enablement / training
8. Something else (describe it)
Your choice:
Goal â “What’s the outcome you want?”
What outcome should this deck drive?
1. Close a deal / advance an opportunity
2. Educate / enable a team
3. Get executive buy-in
4. Win a competitive deal
5. Launch a product or campaign
6. Other (describe it)
Your choice:
Audience â “Who is this for?”
Who's the audience?
Provide any of the following:
⢠Company name or domain (e.g., acme.com)
⢠Person name or email (e.g., jane@acme.com)
⢠Role/title description (e.g., "VP Sales at mid-market SaaS")
⢠General audience (e.g., "internal sales team", "board of directors")
Target:
Content readiness â “How much do you have already?”
How much content do you have?
1. I have content ready â I'll paste or describe it
2. I have rough notes â I'll share, you help me structure
3. Help me figure it out â Octave drives the content strategy
4. I have a PPTX file â convert and enhance it
Your choice:
If a .pptx file is provided, jump to the PPTX Conversion Path before continuing.
Length â “How long should this be?”
If the user provided existing content (PPTX, notes, or pasted content), offer to keep, shorten, or expand:
Your source has ~[N] slides worth of content. What length do you want?
1. Keep similar â stay around [N] slides
2. Shorter â condense to the essentials
3. Longer â expand with more detail and data
4. Custom â I have a specific slide count in mind
Your choice:
If starting from scratch, ask based on purpose:
How long should this deck be?
1. Short (5-8 slides) â punchy, high-impact, perfect for pitches and exec summaries
2. Medium (10-15 slides) â standard for most presentations
3. Long (18-25 slides) â detailed deep-dives, enablement, or QBRs
4. Custom â I have a specific slide count in mind
Your choice:
| Purpose | Recommended Default |
|---|---|
| Customer pitch / pre-demo | Short (5-8) |
| Customer QBR / review | Long (18-25) |
| Internal strategy | Medium (10-15) |
| Conference keynote | Medium (10-15) |
| Product launch / GTM | Long (18-25) |
| Competitive battlecard | Short (5-8) |
| Sales enablement | Long (18-25) |
Use the recommended default as the pre-selected option. If the user picks “Custom,” ask for a target slide count.
Step 2: Octave-Powered Context Gathering
Based on purpose, goal, and audience, use Octave MCP tools to build rich context for the deck. Always tell the user what you’re researching and why.
Call as many tools as needed to build a complete picture. The best decks come from layering multiple sources â company enrichment + playbook messaging + proof points + conversation intel all combine to create slides grounded in real data. Don’t stop at one tool when three would give you a stronger narrative.
That said, not every tool applies to every deck. Use your judgment about which are relevant to this specific situation. The tables below show what’s available â pick the combination that gives you the richest context for the deck type and audience.
List vs Search â when to use which:
| Tool | Purpose | Use when… |
|---|---|---|
list_all_entities({ entityType }) |
Fetch all entities of a type (minimal fields) | You want a quick inventory â “show me all our personas” |
list_entities({ entityType }) |
Fetch entities with full data (paginated) | You need the actual content â “get full proof point details” |
get_entity({ oId }) |
Deep dive on one specific entity | You found something relevant and need the complete picture |
search_knowledge_base({ query }) |
Semantic search across library + resources | You have a concept or question â “how do we compete in healthcare?” |
list_resources() / search_resources({ query }) |
Uploaded docs, URLs, Google Drive files | You need reference material, uploaded assets, or source docs |
Rule of thumb: Use list_* when you know what type of thing you want. Use search_* when you know what topic you’re looking for.
Follow-up decks â ground them in what actually happened:
If this deck follows a previous interaction with the account (QBR, follow-up after a demo, deal review, renewal pitch), pull findings and events to anchor the narrative in real data rather than generic positioning:
list_findings({ query: "<company or contact>", startDate: "<relevant period>" })â surfaces what was actually said in calls: objections raised, features requested, pain points confirmed, competitor mentionslist_events({ filters: { accounts: ["<account_oId>"] } })â deal stage changes, meetings held, emails sent â shows the journey so farget_event_detail({ eventOId })â deep dive on specific events (e.g., the discovery call, the demo) to pull exact context
This turns a generic “here’s our product” deck into “here’s what we heard from you, and here’s how we’re addressing it” â much more compelling for the audience.
For Customer-Facing Decks (pitch, demo, QBR)
Start with company and person enrichment, then pull positioning context as needed:
| What you need | Tool | When to use |
|---|---|---|
| Company profile | enrich_company({ companyDomain }) |
Almost always â gives industry, size, tech stack, signals |
| Key contacts | find_person({ searchMode: "people", companyDomain, fuzzyTitles }) |
When audience includes unknown stakeholders |
| Person deep-dive | enrich_person({ person: { email, firstName, lastName, companyDomain } }) |
When a specific person is the target audience |
| ICP fit scoring | qualify_company({ companyDomain }) |
When you need to frame “why us” for this account |
| All playbooks | list_all_entities({ entityType: "playbook" }) |
Quick scan of available playbooks to find the right one |
| Matching playbook | search_knowledge_base({ query: "<industry> <persona>", entityTypes: ["playbook"] }) |
When you have a concept and need the best-fit playbook |
| Playbook details | get_playbook({ oId, includeValueProps: true }) |
After finding a relevant playbook â gets full content + value props |
| Value props | list_value_props({ playbookOId }) |
Fetch value props for a specific playbook (requires playbook oId) |
| All proof points | list_entities({ entityType: "proof_point" }) |
Fetch actual proof points with full data â metrics, quotes, logos |
| All references | list_entities({ entityType: "reference" }) |
Fetch customer references with full details |
| Find proof points by topic | search_knowledge_base({ query: "<industry> results", entityTypes: ["proof_point", "reference"] }) |
When you need proof points about a specific topic or industry |
| Competitive context | search_knowledge_base({ query: "<signals>", entityTypes: ["competitor"] }) |
When competitor is mentioned or likely in the deal |
| Uploaded resources | search_resources({ query: "<topic>" }) |
When the workspace has uploaded docs, one-pagers, or assets relevant to the deck |
| Recent intel | list_findings({ query: "<company>", startDate: "<90 days ago>" }) |
When you want conversation-based insights |
| Synthesized prep | generate_call_prep({ companyDomain }) |
When you want a single comprehensive brief to work from |
For Internal Decks (strategy, planning, launch)
Pull from the library to ground the deck in your actual GTM data:
| What you need | Tool | When to use |
|---|---|---|
| Personas | list_all_entities({ entityType: "persona" }) |
Quick scan of all personas |
| Persona details | list_entities({ entityType: "persona" }) |
Full persona data â pain points, priorities, messaging |
| Segments | list_all_entities({ entityType: "segment" }) |
Quick scan of market segments |
| Competitors | list_all_entities({ entityType: "competitor" }) |
Quick scan of competitive landscape |
| Products | list_all_entities({ entityType: "product" }) |
Quick scan of product capabilities |
| Use cases | list_all_entities({ entityType: "use_case" }) |
When deck covers how customers use the product |
| Entity details | get_entity({ oId }) |
Deep dive on any specific entity found above |
| Positioning by topic | search_knowledge_base({ query: "<topic>", entityTypes: ["playbook", "product"] }) |
When you have a concept and need relevant positioning |
| Proof points | list_entities({ entityType: "proof_point" }) |
Fetch all proof points with full data for credibility slides |
| References | list_entities({ entityType: "reference" }) |
Fetch customer references for social proof slides |
| Value props | list_value_props({ playbookOId }) |
Value props for a specific playbook |
| Uploaded docs | search_resources({ query: "<topic>" }) |
Find uploaded strategy docs, market research, or assets |
| Market signals | list_findings({ query: "<topic>", startDate: "<90 days ago>" }) |
Recent conversation-based trends |
| Deal outcomes | list_events({ startDate: "<90 days ago>", filters: { eventTypes: ["DEAL_WON", "DEAL_LOST"] } }) |
Pipeline, revenue, or win/loss data |
For Competitive Decks (battlecard presentations)
Focus on the specific competitor(s) and evidence from real deals:
| What you need | Tool | When to use |
|---|---|---|
| All competitors | list_all_entities({ entityType: "competitor" }) |
Quick scan of all competitors |
| Competitor full data | list_entities({ entityType: "competitor" }) |
Full competitor profiles â strengths, weaknesses, positioning |
| Competitor deep dive | get_entity({ oId }) |
Everything about one specific competitor |
| Competitive positioning | search_knowledge_base({ query: "<competitor> differentiation", entityTypes: ["playbook", "competitor"] }) |
When you have a concept â “how do we beat them on security?” |
| Our products | list_entities({ entityType: "product" }) |
Full product data for side-by-side comparison slides |
| Proof points (competitive wins) | list_entities({ entityType: "proof_point" }) |
Fetch all proof points â filter for competitive wins |
| Win/loss data | list_events({ filters: { eventTypes: ["DEAL_WON", "DEAL_LOST"], competitors: ["<oId>"] } }) |
Real deal outcomes against this competitor |
| Conversation evidence | list_findings({ query: "<competitor>", eventFilters: { competitors: ["<oId>"] } }) |
Real objections and mentions from calls |
| Value props | list_value_props({ playbookOId }) |
Differentiators from a specific playbook |
| Competitive resources | search_resources({ query: "<competitor>" }) |
Uploaded battlecards, analyst reports, or competitive docs |
For Enablement Decks (training, sales kickoff)
Mix playbook content with real deal examples:
| What you need | Tool | When to use |
|---|---|---|
| All playbooks | list_all_entities({ entityType: "playbook" }) |
Scan available playbooks to decide which to teach |
| Playbook full content | get_playbook({ oId, includeValueProps: true }) |
Full playbook with value props for training slides |
| Playbook by topic | search_knowledge_base({ query: "<topic>", entityTypes: ["playbook"] }) |
When you need the playbook most relevant to a concept |
| Personas | list_entities({ entityType: "persona" }) |
Full persona data for “know your buyer” slides |
| Competitors | list_entities({ entityType: "competitor" }) |
Full competitor data for competitive handling slides |
| All proof points | list_entities({ entityType: "proof_point" }) |
Fetch proof points with full data for example slides |
| Proof points by topic | search_knowledge_base({ query: "results metrics", entityTypes: ["proof_point", "reference"] }) |
When you need proof points about specific outcomes |
| Recent wins | list_events({ filters: { eventTypes: ["DEAL_WON"] } }) |
Success stories to use as examples |
| Win details | get_event_detail({ eventOId }) |
Deep dive on a notable win for a case study slide |
| Training resources | search_resources({ query: "<topic>" }) |
Uploaded enablement docs, playbook PDFs, or training assets |
Output of this step: Present a structured content brief to the user:
DECK OUTLINE: [Title]
=====================
Purpose: [Purpose from Step 1]
Audience: [Target audience]
Goal: [Desired outcome]
Length: [Short/Medium/Long/Custom] â [N] slides
Source: [From scratch / User content / PPTX conversion]
---
NARRATIVE ARC
-------------
1. HOOK â [Opening that captures attention]
2. PROBLEM â [Pain point or challenge]
3. SOLUTION â [How you solve it]
4. PROOF â [Evidence and social proof]
5. ASK â [Clear next step / CTA]
---
SLIDE-BY-SLIDE OUTLINE
-----------------------
Slide 1: [Title Slide]
⢠[Headline]
⢠[Subtitle/context]
Slide 2: [Problem/Challenge]
⢠[Key point 1]
⢠[Key point 2]
⢠[Data point from Octave]
Slide 3: [Solution Overview]
⢠[Value prop 1]
⢠[Value prop 2]
⢠[Value prop 3]
[Continue for all slides...]
---
Octave Sources Used:
⢠Company profile: [Company name] â [key insights]
⢠Playbook: [Playbook name] â [key messaging angle]
⢠Proof points: [N] references pulled
⢠Competitive intel: [If applicable]
⢠Findings: [N] recent signals
---
Does this outline look good? I can:
1. Proceed to style selection and generation
2. Add/remove/reorder slides
3. Go deeper on any section
4. Change the narrative angle
Wait for user approval before proceeding.
Step 3: Brand Discovery (Optional)
Ask the user:
Do you want to use your company's brand styling?
1. Yes â extract from my website (provide URL)
2. Yes â I'll provide brand assets (colors, fonts, logo)
3. No â I'll pick from style presets
4. Use Octave brand styling
Your choice:
If user wants brand extraction:
Tier 1: browser-use (best quality, if available)
1. browser-use open <website-url>
2. browser-use screenshot brand-capture.png
3. browser-use eval "(() => {
const styles = getComputedStyle(document.documentElement);
const body = getComputedStyle(document.body);
return {
bgColor: body.backgroundColor,
textColor: body.color,
fontFamily: body.fontFamily,
links: getComputedStyle(document.querySelector('a') || document.body).color,
headings: getComputedStyle(document.querySelector('h1,h2,h3') || document.body).fontFamily,
logos: [...document.querySelectorAll('img[src*=logo], svg[class*=logo], header img')].map(e => e.src || 'inline-svg').slice(0, 3)
};
})()"
4. browser-use extract "List the primary brand colors (hex), fonts, and logo URLs visible on this page"
5. Combine extractions into brand config
6. Show to user for confirmation
Tier 2: WebFetch (if browser-use unavailable)
1. WebFetch the homepage URL
2. Parse HTML/CSS for:
- CSS custom properties (--brand-*, --color-*, --primary, etc.)
- font-family declarations from body, h1-h3
- Logo URLs from <img>, <svg>, og:image meta tags
- meta theme-color
3. Show extracted brand config to user for confirmation
Tier 3: Manual (if neither works)
I couldn't automatically extract your brand. You can:
1. Share your brand guidelines (PDF or link)
2. Provide hex colors: primary, secondary, background, text
3. Name your fonts (heading + body)
4. Share logo files
5. Try coolors.co/image-picker with a screenshot of your site
Provide what you have:
Always confirm the brand config with the user before proceeding:
BRAND CONFIG EXTRACTED
======================
Colors:
Primary: #XXXXXX ââ
Secondary: #XXXXXX ââ
Background: #XXXXXX ââ
Text: #XXXXXX ââ
Accent: #XXXXXX ââ
Fonts:
Headings: [Font name]
Body: [Font name]
Logo: [URL or file path]
Does this look right? (y/n/adjust)
Step 4: Style Selection
Ask the user how they want to choose their style:
How would you like to choose your style?
1. Show me options â I'll generate preview slides based on your mood
2. I know what I want â pick from 12 presets
3. Use my brand â auto-generate from brand extraction
4. Surprise me â I'll pick based on your deck purpose
Your choice:
Option 1: Mood-Based Previews
Ask:
What impression should the deck make?
1. Impressed â premium, polished, high-stakes
2. Excited â energetic, bold, forward-looking
3. Calm â clean, trustworthy, understated
4. Inspired â creative, visionary, memorable
Your mood:
Generate 3 single-slide HTML preview files based on the mood. Use the first slide from the outline as content. Save to .octave-decks/slide-previews/:
| Mood | Preview Presets |
|---|---|
| Impressed | midnight-pro, executive-dark, octave-brand |
| Excited | electric-studio, neon-pulse, solar-flare |
| Calm | swiss-modern, soft-light, paper-minimal |
| Inspired | dark-botanical, aurora-gradient, monochrome-bold |
If brand was extracted in Step 3, add a 4th brand-themed preview.
Open all previews in the browser for the user to compare, then ask which they prefer.
Option 2: Preset Picker
Show the preset table:
STYLE PRESETS
=============
DARK THEMES
1. midnight-pro â Dark navy, white text, blue accents. Executive feel.
2. executive-dark â Charcoal + gold. Premium boardroom aesthetic.
3. octave-brand â Octave purple on dark navy. Product-aligned.
4. electric-studio â Pure black + electric blue. Tech-forward.
5. neon-pulse â Dark + neon green/cyan. Developer/hacker energy.
6. dark-botanical â Dark + warm gold/rose. Elegant and premium.
LIGHT THEMES
7. swiss-modern â White + red accent. Bauhaus minimal.
8. soft-light â Warm white + sage green. Calm and approachable.
9. paper-minimal â Off-white + black type. Editorial simplicity.
VIBRANT THEMES
10. solar-flare â Deep orange gradients. Bold and energetic.
11. aurora-gradient â Purple-to-teal gradients. Visionary and modern.
12. monochrome-bold â High-contrast B&W. Statement typography.
Your choice (number or name):
Full CSS variable definitions for each preset are in references/style-presets.md.
Option 3: Brand-Generated Style
Auto-generate CSS variables from the brand config extracted in Step 3:
- --bg: [brand background or dark variant]
- --bg-elevated: [slightly lighter than bg]
- --bg-card: [semi-transparent card bg]
- --text-primary: [brand text color]
- --text-secondary: [muted variant]
- --brand-primary: [primary brand color]
- --brand-500: [lighter accent]
- --font-display: [brand heading font]
- --font-body: [brand body font]
Show the generated style to the user for confirmation.
Option 4: Auto-Pick
Map deck purpose to recommended presets:
| Purpose | Recommended Preset |
|---|---|
| Customer pitch | midnight-pro |
| Customer QBR | executive-dark |
| Internal strategy | octave-brand |
| Conference keynote | electric-studio |
| Product launch | aurora-gradient |
| Competitive battlecard | neon-pulse |
| Sales enablement | soft-light |
Tell the user what you picked and why. Let them override.
Step 5: Generate Presentation
Build a single, self-contained HTML file. No external dependencies. Everything inlined.
Output Directory
Every deck gets its own folder under .octave-decks/:
.octave-decks/
âââ slide-previews/ # temp style previews (cleaned up after selection)
âââ <kebab-case-name>-<YYYY-MM-DD>/ # one folder per deck
âââ <name>.html # final HTML presentation
âââ <name>.pptx # PPTX export (if requested)
âââ <name>-carousel.html # LinkedIn carousel version (if requested)
âââ <name>-content.md # markdown export (if requested)
âââ assets/ # images (from PPTX conversion or user-provided)
Example: /octave:deck "pitch for Acme Corp" â .octave-decks/acme-corp-pitch-2026-02-07/acme-corp-pitch.html
The entire .octave-decks/ directory is in .gitignore â nothing here gets committed.
HTML Architecture
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[Deck Title]</title>
<!-- Google Fonts (preconnect + stylesheet) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=[fonts]&display=swap" rel="stylesheet">
<style>
/* === CSS Variables (from chosen preset) === */
:root { ... }
/* === Reset & Base === */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-snap-type: y mandatory; scroll-behavior: smooth; }
/* === Slide Container === */
.slide {
height: 100vh;
height: 100dvh;
width: 100%;
scroll-snap-align: start;
overflow: hidden;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
/* === Typography (all clamp-based) === */
.heading-1 { font-size: clamp(2rem, 5vw, 4rem); }
.heading-2 { font-size: clamp(1.5rem, 3.5vw, 2.75rem); }
.heading-3 { font-size: clamp(1rem, 2vw, 1.5rem); }
.body-text { font-size: clamp(0.85rem, 1.4vw, 1.05rem); }
/* === Layout Utilities === */
.slide-inner { max-width: 1100px; width: 100%; padding: clamp(1.5rem, 4vh, 3rem) clamp(2rem, 5vw, 6rem); }
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(1rem, 2vw, 2rem); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1rem, 2vw, 2rem); }
/* === Components (cards, pills, metrics, etc.) === */
/* === Animations === */
/* === Navigation (progress bar + nav dots) === */
/* === Responsive (max-height media queries) === */
/* === prefers-reduced-motion === */
</style>
</head>
<body>
<div id="progress-bar"></div>
<nav id="nav-dots"></nav>
<!-- Slides -->
<section class="slide" data-slide="0">
<div class="bg-mesh">...</div>
<div class="slide-inner">
<!-- Slide content -->
</div>
</section>
<!-- Repeat for each slide -->
<script>
// Navigation: keyboard (ArrowDown/Up, Space, PageDown/Up), scroll snap, touch
// Progress bar animation
// Nav dots generation and active state
// Intersection Observer for .animate-in elements
// prefers-reduced-motion check
</script>
</body>
</html>
Viewport Fitting Requirements (Critical)
These rules are non-negotiable. Every slide must fit within 100vh/100dvh without scrolling:
- All font sizes use
clamp()â responsive to viewport, never fixed px - All spacing uses
clamp()â padding, margins, gaps scale with viewport - Content density limits per slide type:
| Slide Type | Max Content |
|---|---|
| Title | 1 heading + 1 subtitle (2-3 lines max) |
| Section Divider | 1 big heading + 1 subtitle. Chapter break. |
| Content | 1 heading + 4-6 bullet points |
| Grid/Cards | 1 heading + 6 cards maximum |
| Quote | 1 quote (3 lines max) + attribution |
| Metric | 1 heading + 3-4 big numbers |
| Comparison | 1 heading + 2-column layout (6 rows max) |
| Timeline/Process | 1 heading + 4-6 steps (label + short description each) |
| Logo Wall | 1 heading + 8-12 logos in a grid |
| Image | 1 heading + 1 image + 1 caption |
| Agenda/TOC | 1 heading + 5-8 agenda items |
| CTA/Closing | 1 heading + 1-2 lines + 1 action |
- If content exceeds limits â split into multiple slides. Never overflow.
- Media queries for short viewports:
@media (max-height: 700px) { /* Reduce font sizes ~10% */ } @media (max-height: 600px) { /* Reduce further, tighten padding */ } @media (max-height: 500px) { /* Minimal mode */ } overflow: hiddenon every.slideâ content that doesn’t fit is invisible, so it must fit
Animation Patterns
Staggered entrance animations triggered by Intersection Observer:
.slide .animate-in {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}
.slide.visible .animate-in {
opacity: 1;
transform: translateY(0);
}
/* Stagger children */
.slide.visible .animate-in:nth-child(1) { transition-delay: 0.1s; }
.slide.visible .animate-in:nth-child(2) { transition-delay: 0.2s; }
.slide.visible .animate-in:nth-child(3) { transition-delay: 0.3s; }
/* ... up to 8 */
Additional animation options (use sparingly):
- Counter animation for metrics: numbers count up when slide visible
- Draw-in for borders/lines: width/height transitions from 0
- Fade-scale for cards:
transform: scale(0.95)toscale(1)
Always respect prefers-reduced-motion:
@media (prefers-reduced-motion: reduce) {
.slide .animate-in { opacity: 1; transform: none; transition: none; }
}
Navigation Implementation
// Generate nav dots from slide count
// Scroll snap handles primary navigation
// Keyboard: ArrowDown/Right/Space = next, ArrowUp/Left = prev
// Progress bar: width = (currentSlide / totalSlides) * 100%
// Intersection Observer triggers .visible class for animations
// Touch support via scroll snap (native)
Slide Type Templates
Consult references/slide-templates.md for HTML templates for each slide type: title, content, grid/card, metric, quote, comparison, section divider, timeline, logo wall, image, agenda, and CTA. Mix types for visual variety.
Step 6: Delivery
After generating the HTML file:
- Clean up any preview files from
.octave-decks/slide-previews/ - Open the presentation in the default browser
- Present a summary:
PRESENTATION READY
==================
Folder: .octave-decks/<deck-name>-<date>/
File: .octave-decks/<deck-name>-<date>/<deck-name>.html
Slides: [N] slides
Style: [Preset name or "Custom Brand"]
Size: [file size]
Navigation:
⢠Scroll or swipe to navigate between slides
⢠Keyboard: Arrow keys, Space, Page Up/Down
⢠Click nav dots on the right edge
Customization tips:
⢠Colors: Edit the :root CSS variables at the top of the file
⢠Content: Each <section class="slide"> is one slide
⢠Fonts: Change the Google Fonts <link> and font-family values
⢠Add slides: Copy a <section> block, increment data-slide
---
Want me to:
1. Adjust specific slides
2. Change the style/colors
3. Add or remove slides
4. Create a version for a different audience
5. Export to another format (PPTX, PDF, LinkedIn Carousel, Google Slides, Gamma)
6. Done
Step 7: Export (Optional)
Consult references/export-guide.md for detailed export instructions for each format: PDF, LinkedIn Carousel, PPTX, Google Slides, Gamma, and Markdown.
PPTX Conversion Path
When a .pptx file is provided:
Extract Content
# Install if needed: pip install python-pptx Pillow
from pptx import Presentation
from pptx.util import Inches, Pt
import json, os
prs = Presentation("input.pptx")
slides = []
deck_dir = ".octave-decks/<deck-name>-<date>"
os.makedirs(f"{deck_dir}/assets", exist_ok=True)
for i, slide in enumerate(prs.slides):
slide_data = {"index": i, "shapes": []}
for shape in slide.shapes:
if shape.has_text_frame:
slide_data["shapes"].append({
"type": "text",
"text": shape.text_frame.text,
"paragraphs": [
{"text": p.text, "level": p.level}
for p in shape.text_frame.paragraphs
]
})
elif shape.shape_type == 13: # Picture
img = shape.image
ext = img.content_type.split("/")[-1]
fname = f"{deck_dir}/assets/slide{i}_img{len(slide_data['shapes'])}.{ext}"
with open(fname, "wb") as f:
f.write(img.blob)
slide_data["shapes"].append({"type": "image", "path": fname})
slides.append(slide_data)
Conversion Flow
- Extract text and images from PPTX using python-pptx
- Save images to the
assets/subdirectory inside the deck folder (.octave-decks/<deck-name>-<date>/assets/) - Show extracted content structure to the user for review
- Still run Step 1 (purpose/goal) â the content comes from the PPTX but context matters
- Still offer Step 3 (brand) â the original PPTX style is lost in conversion
- Proceed to Steps 4-6 as normal, using extracted content instead of Octave-generated content
Note: Images from the PPTX are saved as separate files referenced by the HTML. The output is still a single HTML file, but images are external assets. Mention this to the user.
MCP Tools Used
Research & Enrichment
enrich_company– Full company intelligence profileenrich_person– Full person intelligence reportfind_person– Find contacts at a company by title/rolequalify_company– ICP fit scoring for a companyqualify_person– ICP fit scoring for a personfind_company– Find companies matching criteria
Library â Fetching Entities
list_all_entities– Quick scan of all entities of a type (minimal fields, no pagination)list_entities– Fetch entities with full data and pagination (proof points, references, personas, etc.)get_entity– Deep dive on one specific entityget_playbook– Retrieve a playbook with full content and value propslist_value_props– Value propositions for a specific playbook
Library â Searching
search_knowledge_base– Semantic search across library entities and resourceslist_resources– Browse uploaded docs, URLs, and Google Drive filessearch_resources– Semantic search across uploaded resources
Intelligence & Signals
list_findings– Recent conversation findings and insightslist_events– Deal events (won, lost, created, etc.)get_event_detail– Full details for a specific event
Content Generation
generate_call_prep– Synthesized prep brief for accountsgenerate_content– Generate positioning or messaging contentgenerate_email– Generate email content (for follow-up slides)
Brand & Style
list_brand_voices– Available brand voices in workspacelist_writing_styles– Available writing styles in workspace
Error Handling
Octave Connection Failed:
Could not connect to your Octave workspace.
The deck builder can still work without Octave â you’ll provide the content manually, and I’ll handle structure, style, and HTML generation.
To reconnect: check your MCP configuration or run
/octave:workspace status
Company/Person Not Found:
I couldn’t find detailed intelligence for [target].
Options:
- Proceed with what we have â I’ll use general positioning from your library
- Try a different domain or email
- Provide the content manually and I’ll build the deck
No Matching Playbook:
No playbook matches this audience profile directly.
I’ll use your general value props and positioning. After the deck is built, consider creating a playbook for this segment:
/octave:library create playbook
PPTX Extraction Failed:
Could not parse the PPTX file.
Options:
- Try a different file
- Export as PDF and I’ll work from that
- Copy-paste the content manually
- Describe what the deck covers and I’ll rebuild from scratch
Browser-Use Unavailable (Brand Extraction):
Browser automation isn’t available for brand extraction.
Falling back to web fetch. If that doesn’t capture your brand accurately, you can provide colors and fonts manually.
Style Preview Won’t Open:
Could not open preview files in browser.
Preview files are saved at: [file paths]
Open them manually, or just pick a preset by name/number.
Related Skills
/octave:research– Deep account research (feeds into deck content)/octave:battlecard– Competitive intelligence (for competitive decks)/octave:generate– Generate content with brand voice control/octave:campaign– Campaign strategy (deck as part of campaign)/octave:enablement– Sales enablement content packaging/octave:pmm– Product marketing collateral/octave:insights– Conversation intelligence for data-driven slides/octave:pipeline– Pipeline data for QBR decks