diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b5cf7e2..b4245d2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -54,3 +54,5 @@ body: required: true - label: "I want to work on this issue" required: false + - label: "I am participating in GSSoC 2026" + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 0db54ec..f9b4da5 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -73,4 +73,6 @@ body: required: true - label: "I want to work on this issue" required: false + - label: "I am participating in GSSoC 2026" + required: false diff --git a/.github/ISSUE_TEMPLATE/project_proposal.md b/.github/ISSUE_TEMPLATE/project_proposal.md index 4bdd482..bc45c3f 100644 --- a/.github/ISSUE_TEMPLATE/project_proposal.md +++ b/.github/ISSUE_TEMPLATE/project_proposal.md @@ -104,3 +104,5 @@ body: required: true - label: "I want to work on this issue" required: false + - label: "I am participating in GSSoC 2026" + required: false diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..3535344 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,84 @@ + + +documentation: + - changed-files: + - any-glob-to-any-file: + - '**/*.md' + - 'docs/**' + +python: + - changed-files: + - any-glob-to-any-file: + - '**/*.py' + + +github-actions: + - changed-files: + - any-glob-to-any-file: + - '.github/**' + + +enhancement: + - changed-files: + - any-glob-to-any-file: + + - 'src/**' + - '*/**.py' + +beginner: + - changed-files: + + - any-glob-to-any-file: + - '**/*.md' + +intermediate: + + - changed-files: + - any-glob-to-any-file: + - '**/*.py' + + +advanced: + - changed-files: + - any-glob-to-any-file: + - '.github/**' + - 'tests/**' + +"type:design": + - changed-files: + - any-glob-to-any-file: + - 'web-app/**' + - 'web-app/*.html' + - 'web-app/js/**' + - 'web-app/css/**' + +"type:feature": + - changed-files: + - any-glob-to-any-file: + - '**/*.py' + +"type:docs": + - changed-files: + - any-glob-to-any-file: + - '**/*.md' + - 'README.html' + - 'docs/**' + +"type:devops": + - changed-files: + - any-glob-to-any-file: + - '.github/**' + - '.github/workflows/**' + +"type:refactor": + - changed-files: + - any-glob-to-any-file: + - '**/*.py' + - 'web-app/**' + +"type:bug": + - changed-files: + - any-glob-to-any-file: + - '**/*.py' + - 'tests/**' + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index a9a32ea..4d9fe62 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -75,3 +75,5 @@ body: required: false - label: "I have updated the README.md (if adding new project)" required: false + - label: "I am participating in GSSoC 2026" + required: false diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml new file mode 100644 index 0000000..6ad7e93 --- /dev/null +++ b/.github/workflows/contributors.yml @@ -0,0 +1,86 @@ +name: contributor automation + +on: + schedule: # runs daily at midnight + - cron: '0 0 * * *' + pull_request: + types: [closed] + branches: + - main + + # allows manual trigger +permissions: + contents: write + +jobs: + update-readme: + if: github.event_name != 'pull_request' || github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Fetch Merged PR Authors (Pagination) + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + PAGE=1 + echo "[]" > final_list.json + while true; do + # Using pulls endpoint to capture only merged contributors + RESPONSE=$(gh api "/repos/steam-bell-92/python-mini-project/pulls?state=closed&per_page=100&page=${PAGE}") + COUNT=$(echo "$RESPONSE" | jq '. | length') + if [ "$COUNT" -eq 0 ]; then break; fi + jq -s '.[0] + .[1]' final_list.json <(echo "$RESPONSE") > tmp.json && mv tmp.json final_list.json + PAGE=$((PAGE + 1)) + done + # Filters for actual merged PRs and unique users + jq '[.[] + | select(.merged_at != null and .user != null and .user.type != "Bot") + | .user.login] + | unique + | sort' final_list.json > contributors.json + - name: Build Gallery HTML + run: | + set -euo pipefail + GALLERY_HTML="" + for USERNAME in $(jq -r '.[]' contributors.json); do + GALLERY_HTML="${GALLERY_HTML}\"${USERNAME}\"" + done + echo "$GALLERY_HTML" > gallery_fragment.txt + + - name: Update README.md + run: | + set -euo pipefail + # Safety check for markers + start_count=$(grep -c '' README.md || true) + end_count=$(grep -c '' README.md || true) + if [ "$start_count" -ne 1 ] || [ "$end_count" -ne 1 ]; then + echo "Error: README.md must contain exactly one pair of markers." + exit 1 + fi + + start_line=$(grep -n '' README.md | cut -d: -f1) + end_line=$(grep -n '' README.md | cut -d: -f1) + if [ "$start_line" -ge "$end_line" ]; then + echo "Error: CONTRIBUTORS_START must appear before CONTRIBUTORS_END." + exit 1 + fi + + sed -i '//,// { + //! { //! d; } + }' README.md + sed -i '//r gallery_fragment.txt' README.md + + - name: Commit and Push + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add README.md + if git diff --staged --quiet; then + echo "No changes to README." + else + git commit -m "docs: update contributor gallery" + git push + fi diff --git a/.github/workflows/gssoc-labeler.yml b/.github/workflows/gssoc-labeler.yml new file mode 100644 index 0000000..cdc3eab --- /dev/null +++ b/.github/workflows/gssoc-labeler.yml @@ -0,0 +1,45 @@ +name: GSSoC Labeler + +on: + issues: + types: [opened, edited] + pull_request_target: + types: [opened, edited] + +jobs: + label_gssoc: + runs-on: ubuntu-latest + + permissions: + issues: write + pull-requests: write + + steps: + - name: Check and add GSSoC label + uses: actions/github-script@v7 + with: + script: | + let bodyText = ""; + let issueNum = null; + + if (context.payload.issue?.body) { + bodyText = context.payload.issue.body; + issueNum = context.payload.issue.number; + } + else if (context.payload.pull_request?.body) { + bodyText = context.payload.pull_request.body; + issueNum = context.payload.pull_request.number; + } + + const isGSSoC = + bodyText.includes("[x] I am participating in GSSoC 2026") || + bodyText.includes("[X] I am participating in GSSoC 2026"); + + if (isGSSoC && issueNum) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNum, + labels: ["gssoc:accepted"], + }); + } diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000..2756720 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,69 @@ +name: Auto Label Issues and PRs + +on: + pull_request: + types: [opened, synchronize, reopened] + issues: + types: [opened, reopened] + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + label-pr: + name: Label Pull Requests + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Apply labels based on changed files + uses: actions/labeler@v5 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: .github/labeler.yml + + label-issue: + name: Label Issues + runs-on: ubuntu-latest + if: github.event_name == 'issues' + steps: + - name: Label new issues with gssoc26 + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issue = context.payload.issue; + const body = (issue.body || '').toLowerCase(); + const title = (issue.title || '').toLowerCase(); + + const labelsToAdd = ['gssoc26']; + + if (title.includes('bug') || body.includes('bug')) { + labelsToAdd.push('bug'); + } + if (title.includes('feature') || body.includes('enhancement')) { + labelsToAdd.push('enhancement'); + } + if (title.includes('docs') || body.includes('documentation')) { + labelsToAdd.push('documentation'); + } + if (title.includes('level 1') || body.includes('level 1')) { + labelsToAdd.push('level1'); + } + if (title.includes('level 2') || body.includes('level 2')) { + labelsToAdd.push('level2'); + } + if (title.includes('level 3') || body.includes('level 3')) { + labelsToAdd.push('level3'); + } + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: labelsToAdd + }); diff --git a/.github/workflows/pr-merged-thanks.yml b/.github/workflows/pr-merged-thanks.yml index 957008f..abd145f 100644 --- a/.github/workflows/pr-merged-thanks.yml +++ b/.github/workflows/pr-merged-thanks.yml @@ -8,7 +8,9 @@ jobs: thank-contributor: if: github.event.pull_request.merged == true runs-on: ubuntu-latest + permissions: + pull-requests: write issues: write steps: @@ -16,18 +18,17 @@ jobs: uses: actions/github-script@v7 with: script: | - github.rest.issues.createComment({ + await github.rest.issues.createComment({ issue_number: context.payload.pull_request.number, owner: context.repo.owner, repo: context.repo.repo, - body: | - šŸŽ‰ **Thank you for your contribution!** + body: `šŸŽ‰ **Thank you for your contribution!** - Your Pull Request has been merged successfully. + Your Pull Request has been merged successfully. - We appreciate the time and effort you put into improving this project. Contributions like yours help the repository grow and stay useful for everyone. + We appreciate the time and effort you put into improving this project. Contributions like yours help the repository grow and stay useful for everyone. - If you'd like to contribute again, please check the open issues and make sure you are assigned before opening another Pull Request. + If you'd like to contribute again, please check the open issues and make sure you are assigned before opening another Pull Request. - Thanks again for your support! šŸ™Œ - }) + Thanks again for your support! šŸ™Œ` + }); diff --git a/.gitignore b/.gitignore index b7faf40..41e7fdf 100644 Binary files a/.gitignore and b/.gitignore differ diff --git a/.local/secondary_skills/LICENSE.txt b/.local/secondary_skills/LICENSE.txt new file mode 100644 index 0000000..2c6c47b --- /dev/null +++ b/.local/secondary_skills/LICENSE.txt @@ -0,0 +1,21 @@ +Copyright (c) 2026 Replit, Inc. All rights reserved. + +The contents of this directory are proprietary to Replit, Inc. and are +licensed for use solely within the Replit platform under the applicable +Replit user terms. Use of the contents of this directory within the +Replit platform, including by Replit users for commercial purposes, is +unlimited and expressly permitted. + +Outside of the Replit platform, the contents of this directory are +licensed under the Creative Commons Attribution-NonCommercial 4.0 +International License (CC BY-NC 4.0). You may obtain a copy of that +license at: +https://creativecommons.org/licenses/by-nc/4.0/ + +Under CC BY-NC 4.0, you may share and adapt the contents of this +directory for non-commercial purposes, provided you appropriately credit +Replit, Inc. and indicate if changes were made. Commercial use of the +contents of this directory outside of the Replit platform is strictly +prohibited without a separate license from Replit, Inc. + +For commercial licensing inquiries, contact: support@replit.com diff --git a/.local/secondary_skills/ad-creative/.fingerprint b/.local/secondary_skills/ad-creative/.fingerprint new file mode 100644 index 0000000..8dc23b8 --- /dev/null +++ b/.local/secondary_skills/ad-creative/.fingerprint @@ -0,0 +1 @@ +9ddf6593609d4d0fcb1ab58f575522cd \ No newline at end of file diff --git a/.local/secondary_skills/ad-creative/SKILL.md b/.local/secondary_skills/ad-creative/SKILL.md new file mode 100644 index 0000000..b9dded7 --- /dev/null +++ b/.local/secondary_skills/ad-creative/SKILL.md @@ -0,0 +1,872 @@ +--- +name: ad-creative +description: Design static ad creatives for social media and display advertising campaigns. +--- + +# Ad Creative Maker + +Design static ad creatives for social media ads, display banners, and digital advertising campaigns. Build production-ready ads via the design subagent and present them as iframes on the canvas. + +## When to Use + +- User needs ad creatives for Facebook, Instagram, LinkedIn, Google Display, or TikTok +- User wants banner ads or display advertising assets + +- User needs multiple ad variants for A/B testing +- User wants ad copy and visual design together + +- User wants to iterate on ad creative based on performance data +- User asks for carousel ads (Instagram, Facebook, X/Twitter) + +- User wants retargeting/remarketing ad creatives +- User provides their own product photos or brand images and wants ads built around them + +- User needs ads in multiple sizes/formats (square + portrait + landscape) +- User wants a product launch or teaser campaign + +- User wants seasonal or holiday-themed ads +- User needs app install ad creatives + +- User wants to refresh or update existing ads without performance data +- User asks to make ads that match their website's look and feel + +## When NOT to Use + +- Organic social media content (use content-machine skill) +- Video ads or animated content (use storyboard skill for planning) + +- Full landing pages (use the artifacts skill) + +## Golden Rules (check before every ad) + +1. **<20 words total on the image** — everything else goes in primary text / description fields +2. **Only 4 elements per ad**: Logo, Hero, Benefit line, CTA button + +3. **Flat solid background colors only** — no gradients, no patterns, no textures (exception: awareness/launch ads may use a hero image as the background) +4. **Real brand logo, always** — never substitute plain text for a logo (see Logo Extraction below) + +5. **Left-align content** — logo top-left, text left-aligned, CTA left-aligned. Centered layouts look generic. + +## Methodology + +### Step 1: Creative Brief + +Gather: Platform and Format, Objective, Target audience, Key message, CTA, Brand assets, Performance data (if iterating). + +**Brand research (mandatory before building):** Always use web search to look up the brand's actual visual identity before designing. Search for `[brand] brand font typeface typography`and`[brand] brand colors hex`. Use the brand's real fonts, colors, and visual language — never guess or substitute generic alternatives. If the official fonts are commercial/licensed, find the closest Google Fonts alternatives used in the brand's own guidelines. Common pairings: a sans-serif for headlines (e.g., Poppins) and a serif for body text (e.g., Lora). Include these in the subagent task instructions so every angle uses the correct brand identity. + +**Font loading (mandatory in every ad HTML):** After identifying the brand's fonts (or closest Google Fonts alternatives), include them in the head of every ad HTML file: + +```html + + + + + + + + + + + + + +``` + +Always specify the exact weights needed (400, 700, 900). Never rely on browser defaults or system fonts — every ad must load its fonts explicitly. + +**Extract real brand colors from the site (mandatory).** Do not trust web search results for colors — they are frequently wrong. Instead, fetch the actual CSS from the brand's website: + +```bash + +curl -s -L "https://brand.com" | grep -iE '(theme-color|TileColor|mask-icon.*color)' | head -5 + +curl -s -L "https://brand.com" | tr -d '\n' | grep -oP 'href="[^"]*\\css[^"]*"' | head -3 + +curl -s "https://brand.com/path/to/style.css" | grep -oP '#[0-9a-fA-F]{3,8}' | sort -u + +``` + +### Step 2: Platform Specifications (2025-2026) + +#### Meta (Facebook/Instagram) — Visual + +| Placement | Dimensions | Safe zone | + +|---|---|---| + +| Feed (square) | 1080x1080 | ~100px margin all edges | + +| Feed (portrait) — **preferred** | 1080x1350 (4:5) | 4:5 outperforms 1:1 on CTR | + +| Stories | 1080x1920 | Top 14% + bottom 20% = dead zones | + +| Reels | 1080x1920 | Top 14% + bottom 35% = dead zones | + +| **Universal safe core**|**1010x1280 centered** | Works across all placements | + +Upload at 2x pixel density for Retina sharpness. JPG/PNG, 30MB max. + +#### Meta — Text + +| Element | Limit | Notes | + +|---|---|---| + +| Primary text | ~72 chars visible in Reels / 125 in Feed | Write for 72 | + +| Headline | 40 chars rec | Below image | + +| Description | 30 chars rec | Often hidden on mobile | + +#### Google Ads + +**RSA:** Headlines 30 chars (each must work standalone — Google mixes randomly), Descriptions 90 chars, up to 15 headlines / 4 descriptions. Pin sparingly — pinning drops Ad Strength. + +**RDA:** Landscape 1200x628 (1.91:1), Square 1200x1200 (required), Portrait 1200x1500 (4:5, optional). Short headline 30 chars, Long headline 90 chars, Description 90 chars. All images 5MB or less, keep under 150KB for fast load. + +**Highest-inventory static sizes** (if uploading fixed banners): 300x250, 728x90, 320x50, 300x600, 336x280. + +**Performance Max:** Same asset pool serves across Search/Display/YouTube/Gmail/Maps/Discover. Upload all 3 image ratios + a YouTube video — don't let Google auto-generate one. + +#### LinkedIn Ads + +Intro text 150 chars rec (600 max), Headline 70 chars rec (200 max), Image 1200x627 or 1200x1200. + +#### TikTok Ads + +1080x1920 (9:16), Ad text 100 chars max (~80 visible). Spark Ads (boosting organic creator posts) outperform In-Feed Ads on engagement. + +#### X / Twitter Ads + +| Placement | Dimensions | + +|---|---| + +| Single image | 1200x675 (1.91:1) or 1080x1080 (1:1) | + +| Carousel cards | 1080x1080 (1:1), 2-6 cards | + +| Portrait | 1080x1350 (4:5) | + +Tweet text 280 chars (~100 visible with media). Card headline 70 chars. + +### Step 3: Determine Campaign Mode + +Before defining angles, determine whether this is **direct-response**or**awareness/launch**. + +#### Direct-Response (default) + +Use for conversion, lead generation, app installs, purchases. This is the default — most ad requests are direct-response. + +#### Awareness / Launch Campaigns + +Use for product launches, brand announcements, event teasers, top-of-funnel awareness. Prioritize mood and brand impression over clicks. + +##### Key differences from direct-response + +- **No CTA button on the image.** The CTA lives in the post text or link, not the visual. +- **Even less text: ~10-15 words max** — typically brand name, one positioning line, and a date/tagline. + +- **Visual metaphor over product shots.** Use evocative imagery that communicates feeling or aspiration. +- **Multiple visual worlds per campaign.** For carousels or multi-asset campaigns, create 3-5 distinct aesthetic treatments — different palettes, subjects, moods — while keeping typography and logo placement consistent. + +- **Layout pattern:** Logo (top corner) then Hero visual (fills most of the frame) then Brand name/headline (bottom, large, bold) then Subtitle + date (smaller, below headline). +- **Hero images allowed.** Unlike direct-response, awareness ads may use a full-bleed generated image as the background (see Image Guidance below). + +**When to use awareness mode:** Pre-launch teasers, brand-building campaigns, event promotion, or when the user says "announce," "tease," "launch," or asks for something "premium" without conversion goals. + +### Step 3b: Define Angles + +Before writing individual copy, establish 3-5 distinct angles — different reasons someone would click: + +| Category | Example | + +|----------|---------| + +| Pain point | "Stop wasting time on X" | + +| Outcome | "Achieve Y in Z days" | + +| Social proof | "Join 10,000+ teams who..." | + +| Curiosity | "The X secret top companies use" | + +| Identity | "Built for [specific role/type]" | + +| Urgency | "Limited time: get X free" | + +| Contrarian | "Why [common practice] doesn't work" | + +**For retargeting ads**, adjust angles for warm audiences who already know the brand: + +- Reminder: "Still thinking about X?" +- Incentive: "Come back for 15% off" + +- Social proof: "See why 10,000 others chose us" +- Scarcity: "Only 3 left in your size" + +- Objection handling: "Free returns, no risk" + +### Step 4: Design Principles + +- **Under 20 words total on the image** — this is the most important rule. Icons, stats rows, feature grids, and badges all violate this. If it doesn't fit in Logo + Hero + Benefit + CTA, it belongs in the primary text. +- Visual hierarchy: Logo (top-left) then Hero element then Benefit then CTA + +- WCAG 4.5:1 contrast minimum +- CTA: contrasting color, rounded corners, verb-first, left-aligned + +- **No gradients** — flat solid colors only. Use different solid colors across ads for variety. Exception: awareness/launch ads may use a bottom readability gradient over a hero image. + +### Steps 5-6: Generate and Validate Copy + +Vary word choice, specificity, tone, and structure across angles. Always validate character counts before delivering. Include counts in your output. + +```text + +## Angle: [Pain Point — Manual Reporting] + +### Headlines (30 char max) + +1. "Stop Building Reports by Hand" (29) +2. "Automate Your Weekly Reports" (28) + +3. "Reports in 5 Min, Not 5 Hrs" (27) + +### Descriptions (90 char max) + +1. "Marketing teams save 10+ hours/week with automated reporting. Start free." (73) +2. "Connect your data sources once. Get automated reports forever. No code required." (80) + +``` + +### Step 7: Build Ad Creatives + +#### File Setup + +Place all ad HTML files in `artifacts/mockup-sandbox/public/ads/`— served by the mockup-sandbox Vite dev server at`/__mockup/ads/filename.html`. + +After copying image assets from `attached_assets/`, always fix permissions: + +```bash + +chmod 644 artifacts/mockup-sandbox/public/ads/*.png artifacts/mockup-sandbox/public/ads/*.jpg + +``` + +Files copied from `attached_assets/`default to`rw-------` (unreadable by the server). + +#### Cache Busting + +Canvas iframes cache aggressively. After editing any ad file, increment `?v=N` on the iframe URL: + +```text + +https://your-domain.dev/__mockup/ads/angle1.html?v=2 + +``` + +#### Parallel Subagents — Full Task Template + +Launch one design subagent per angle simultaneously. Each subagent gets a complete, self-contained task with all brand details, the HTML structure, and styling rules baked in. **Do not assume the subagent knows any of the golden rules — repeat them explicitly.** + +```javascript + +await startAsyncSubagent({ + +task: `Create a production-ready ad creative as a standalone HTML file. + +**Brand:** + +- Name: [Brand Name] +- Primary color: [hex] | Secondary: [hex] | Accent: [hex] + +- Headline font: [Font Name] (Google Fonts — load via link tag in head) +- Body font: [Font Name] (Google Fonts — load via link tag in head) + +- Logo: [inline SVG code or path to logo file] + +**Ad Details:** + +- Platform: [Meta Feed / Google Display / LinkedIn / TikTok / X] +- Angle: [Pain Point / Outcome / Social Proof / etc.] + +- Headline: "[exact headline text]" +- Benefit: "[one short benefit line]" + +- CTA: "[verb-first CTA text]" +- Background color: [hex — flat solid, NO gradients] + +**File:** Write to artifacts/mockup-sandbox/public/ads/[filename].html + +**MANDATORY HTML STRUCTURE — follow exactly:** + +The ad must use this structure: + +- html/body: width 100vw, height 100vh, overflow hidden, margin 0, padding 0 +- .ad container: width 100vw, height 100vh, solid background color (NO gradients), flex column, justify-content space-between, padding 6vh 7vw + +- .logo: top-left, inline SVG at height 5vh +- .middle: flex column, gap 3vh, containing headline, benefit, and CTA + +- .headline: brand headline font, font-size 8vw, font-weight 900, line-height 1.1 +- .benefit: brand body font, font-size 3vw, slightly transparent white + +- .cta: inline-block, padding 2vh 5vw, accent color background, border-radius 1vw, font-weight 700, align-self flex-start (LEFT-ALIGNED) +- .footer: font-size 1.8vw, subtle color, brand URL + +**RULES — do not violate:** + +- Only 4 elements: Logo, Headline, Benefit, CTA. No icons, stats, badges, feature grids, or dividers. +- Under 20 words total visible on the ad. + +- Flat solid background color — NO gradients, NO patterns. +- All sizing in vw/vh — NO fixed pixel dimensions. + +- Left-align everything — logo top-left, text left-aligned, CTA left-aligned. Do NOT center. +- Load fonts from Google Fonts in the head. Do NOT use system fonts or Inter. + +- The CTA button must use a contrasting accent color and be verb-first.`, + +specialization: "DESIGN", + +relevantFiles: ["artifacts/mockup-sandbox/public/ads/[filename].html"] + +}); + +// Repeat for each angle — all launch simultaneously + +``` + +After launching, call the `wait_for_background_tasks` tool to wait for every ad-design subagent. Then embed each ad as an iframe on the canvas using `apply_canvas_actions`, and call `presentArtifact({ artifactId, shapeIds: [...] })` with the IDs of the new iframe shapes. + +#### Viewport-Relative Sizing (mandatory) + +```css + +html, body { + +margin: 0; padding: 0; + +width: 100vw; height: 100vh; + +overflow: hidden; + +} + +``` + +All internal sizing must use vw/vh. No fixed pixel dimensions on containers. + +#### Ad HTML Structure (mandatory pattern) + +Every ad must follow this exact structure — 4 elements, no more: + +```html + +
+ + + +
+ +
Hero text here
+ +
One short benefit line.
+ +
Verb-first CTA
+ +
+ +brand.com + +
+ +``` + +```css + +.ad { + +width: 100vw; + +height: 100vh; + +background: \#SOLID_COLOR; + +display: flex; + +flex-direction: column; + +justify-content: space-between; + +padding: 6vh 7vw; + +box-sizing: border-box; + +} + +.middle { + +display: flex; + +flex-direction: column; + +gap: 3vh; + +} + +``` + +Do not add icons, stats rows, feature grids, badges, dividers, or any decorative elements. If you are tempted to add a 5th element, move that information to the primary text instead. + +#### Image Guidance + +##### When to use generated images + +- Awareness/launch campaigns — the hero image IS the ad, with text overlaid on a bottom gradient +- When the user explicitly requests photo-based or image-heavy ads + +###### When NOT to use images (default for direct-response) + +- Standard direct-response ads use flat solid color backgrounds with bold typography +- The 4-element rule (Logo, Hero text, Benefit, CTA) works best without competing with a background image + +###### If using a hero image (awareness/launch mode only) + +Generate images using `generateImage`from the media-generation skill. Save to`artifacts/mockup-sandbox/public/images/`and reference via`/__mockup/images/[filename].png`. + +Image prompt strategy: + +- Lead with a specific, tangible subject (object, scene, or person) +- Specify lighting (studio, dramatic, golden hour, Rembrandt) + +- Specify camera quality ("shot on Hasselblad," "editorial photography") +- Add negative prompts: "text, words, letters, logos, watermark, blurry, low quality, cartoon, illustration" + +- Each ad should use a different visual metaphor — same brand, different visual world + +Image-first HTML structure (awareness/launch only): + +```css + +.ad { + +width: 100vw; height: 100vh; + +position: relative; overflow: hidden; + +} + +.hero-img { + +position: absolute; inset: 0; + +width: 100%; height: 100%; + +object-fit: cover; + +} + +.gradient-overlay { + +position: absolute; bottom: 0; width: 100%; + +height: 50vh; + +background: linear-gradient(transparent, rgba(0,0,0,0.8)); + +} + +.content { + +position: absolute; bottom: 0; left: 0; + +padding: 6vh 7vw; + +} + +``` + +**If the user provides their own images:** Use the user's images instead of generating new ones. Copy from `attached_assets/`to`artifacts/mockup-sandbox/public/images/`, fix permissions with`chmod 644`, and reference via`/__mockup/images/[filename]`. Use the awareness/launch image-first layout structure above. + +#### Brand Logo Extraction + +Always use the brand's actual logo — never substitute plain text for a logo. + +**Step 1: Extract the SVG directly from the brand's website.** This is the most reliable method — the actual logo is already embedded in their HTML: + +```bash + +curl -s -L "https://brand.com" | tr -d '\n' | grep -oP ']*>.*?' | head -1 > /tmp/brand-logo.svg + +wc -c /tmp/brand-logo.svg + +``` + +Should be over 1KB for a real logo. + +**Step 2: Verify the extracted SVG path data is complete.** SVG path data can be silently truncated during shell extraction. Always verify the max coordinates fit within the viewBox: + +```bash + +node -e " + +const fs = require('fs'); + +const svg = fs.readFileSync('/tmp/brand-logo.svg', 'utf8'); + +const dMatch = svg.match(/d=\([^\\]+)\\/); + +if (dMatch) { + +const d = dMatch[1]; + +console.log('Path data length:', d.length); + +console.log('Last 80 chars:', d.slice(-80)); + +const nums = d.match(/[\d.]+/g).map(Number); + +const maxX = Math.max(...nums.filter((_, i) => i % 2 === 0)); + +console.log('Max X:', maxX); + +} + +" + +``` + +If path data length is under ~2000 characters for a wordmark logo, the data was likely truncated. Re-extract with a larger buffer. + +**Step 3: Embed inline.** Embedding the SVG directly in the HTML avoids file permission issues, eliminates loading delays, and scales perfectly: + +```html + + + + + + + +``` + +Use `fill="white"`on dark backgrounds,`fill="#BrandDarkColor"` on light backgrounds. + +**Step 4: Position the logo top-left, not centered.** The logo should sit in the top-left corner as part of the visual hierarchy. Do not center-align logos — centered layouts look generic and reduce brand recognition. + +**Fallback: If the website doesn't have an inline SVG**, search for `[brand] logo SVG site:wikimedia.org OR site:brandfetch.com`. As a last resort, use a logo + wordmark pattern with the brand's font. + +**If using an image file for the logo**, always use both max-width and max-height together: + +```css + +.logo-img { + +max-width: 38vw; + +max-height: 12vh; + +width: auto; + +height: auto; + +object-fit: contain; + +} + +``` + +Never use `width: Xvw; height: auto` alone on a square logo — at width 38vw, a square image is also 38vh tall and will overflow its container into content below. + +Logo images have built-in padding. The visible logo mark may only occupy 50-70% of the image dimensions. Size the image larger than you'd expect. + +##### Logos without transparent backgrounds + +| Scenario | Strategy | + +|---|---| + +| Ad bg color matches logo bg exactly | Use that logo version — backgrounds blend seamlessly | + +| White ad background | Use white-background logo + mix-blend-mode: multiply | + +```css + +.logo-img { mix-blend-mode: multiply; } + +``` + +#### Canvas Layout + +Place ad iframes side-by-side in a row for easy comparison. Use square iframes (600x600) so they fit on the canvas without clipping. Space them with ~50px gutters: + +```text + +x=0, y=0: [Iframe: Angle 1] (600x600) + +x=650, y=0: [Iframe: Angle 2] (600x600) + +x=1300, y=0: [Iframe: Angle 3] (600x600) + +``` + +**For portrait/stories ads (9:16):** Use 608x1080 iframes: + +```text + +x=0, y=0: [Iframe: Story 1] (608x1080) + +x=658, y=0: [Iframe: Story 2] (608x1080) + +x=1316, y=0: [Iframe: Story 3] (608x1080) + +``` + +**For multi-format output** (same angle in multiple sizes): Stack formats vertically per angle: + +```text + +x=0, y=0: [Iframe: Angle 1 — Square] (600x600) + +x=0, y=650: [Iframe: Angle 1 — Portrait] (450x600) + +x=650, y=0: [Iframe: Angle 2 — Square] (600x600) + +x=650, y=650: [Iframe: Angle 2 — Portrait] (450x600) + +``` + +**For carousel ads:** Place cards in sequence left-to-right: + +```text + +x=0, y=0: [Iframe: Card 1] (600x600) + +x=650, y=0: [Iframe: Card 2] (600x600) + +x=1300, y=0: [Iframe: Card 3] (600x600) + +x=1950, y=0: [Iframe: Card 4] (600x600) + +``` + +Do not add text labels above iframe shapes — iframes already display their componentName in the title bar. Set componentName to something descriptive like "Angle 1: Outcome — Think deeper. Get further." + +**With landing page mock-ups** (optional — include when the user wants to see the full click-through experience): Place the landing page iframe next to each ad: + +```text + +x=0, y=0: [Iframe: Angle 1 Ad] (600x600) + +x=650, y=0: [Iframe: Angle 1 Landing] (1280x720) + +x=0, y=650: [Iframe: Angle 2 Ad] (600x600) + +x=650, y=650: [Iframe: Angle 2 Landing] (1280x720) + +``` + +The landing page should look like where the ad actually leads — hero section echoing the ad's message, value props, social proof, and a CTA. Not a wireframe. + +#### Export + +Ads use vw/vh sizing so they adapt to any viewport. For export at specific pixel dimensions: + +```bash + +npx playwright screenshot artifacts/mockup-sandbox/public/ads/angle1.html --viewport-size=1080,1080 -o angle1-1080.png + +npx playwright screenshot artifacts/mockup-sandbox/public/ads/angle1.html --viewport-size=1080,1350 -o angle1-portrait.png + +npx playwright screenshot artifacts/mockup-sandbox/public/ads/story1.html --viewport-size=1080,1920 -o story1.png + +``` + +The user can also screenshot each iframe directly from the canvas, or open the HTML files in a browser at the desired size. + +## Prompt-Specific Workflows + +### Carousel Ads + +When the user asks for carousel ads (Instagram, Facebook, X/Twitter): + +1. Each card should be a self-contained visual — assume viewers swipe quickly. +2. Use a **consistent structural layout**across cards (same typography placement, same logo position) with**varying content/colors** per card. This "same but different" effect rewards swiping. + +3. For Instagram/Facebook carousels: 1080x1080 per card, 2-10 cards. +4. For X/Twitter carousels: 1080x1080 per card, 2-6 cards with optional headline/URL per card. + +5. Launch one subagent per card in parallel. Include the card number and total count so the subagent can create a coherent sequence. +6. Arrange cards left-to-right on the canvas so the user can see the swipe flow. + +### Retargeting / Remarketing Ads + +When the user asks for retargeting ads: + +1. Adjust copy for **warm audiences** who already know the brand — don't introduce the brand, remind them. +2. Use retargeting-specific angles: Reminder, Incentive, Social Proof, Scarcity, Objection Handling (see Step 3b). + +3. Consider dynamic elements: "Still interested in [product]?", "Your cart is waiting", etc. +4. Shorter, more direct copy — they already know you. + +### User-Provided Images + +When the user uploads their own product photos or brand images: + +1. Copy from `attached_assets/`to`artifacts/mockup-sandbox/public/images/`. +2. Run `chmod 644` on all copied files. + +3. Use the awareness/launch image-first layout (full-bleed image with gradient overlay and text on top). +4. Do NOT generate new images — use the user's images as-is. + +5. Adapt the text overlay colors to work with the specific image's brightness/contrast. + +### Multi-Format Output + +When the user needs the same ad in multiple sizes: + +1. Create one HTML file per size variant (e.g., `angle1-square.html`,`angle1-portrait.html`,`angle1-landscape.html`). +2. The HTML structure stays the same — vw/vh sizing handles the adaptation. But adjust font sizes and padding for extreme aspect ratios (landscape needs smaller headline vw, portrait can go bigger). + +3. Stack formats vertically per angle on the canvas for easy comparison. +4. Test each format at its target pixel dimensions to verify nothing clips or overflows. + +### Awareness / Launch Campaigns (2) + +When the user asks for a launch, teaser, or brand awareness campaign: + +1. Switch to awareness mode (see Step 3 above). +2. Generate hero images using `generateImage` — each ad should use a different visual metaphor. + +3. Use image-first layout with gradient overlay. +4. No CTA button on the image. ~10-15 words max. + +5. For multi-card campaigns, maintain identical text layout and logo placement across cards while varying the hero visual and color palette. + +### Seasonal / Holiday Ads + +When the user asks for holiday or seasonal ads: + +1. Use the standard methodology but adjust angles for urgency and timeliness. +2. Incorporate seasonal colors subtly — don't overwhelm the brand identity. The brand's colors should still dominate; seasonal colors are accents. + +3. Include time-bound CTAs: "Order by Dec 15 for guaranteed delivery", "48-hour flash sale". +4. Consider the platform's ad approval timeline — submit 3-5 days before the holiday. + +### App Install Ads + +When the user asks for app install ad creatives: + +1. CTA should be app-specific: "Download Free", "Get the App", "Try It Free". +2. Consider showing a device mockup or screenshot (if the user provides one). + +3. For Google App Campaigns: supply landscape (1200x628), portrait (1200x1500), and square (1200x1200) images. +4. Keep the value proposition ultra-clear — users decide in 1-2 seconds whether to install. + +### Refreshing Existing Ads + +When the user wants to update or refresh existing ads without performance data: + +1. Review the existing ads (ask the user to share them or describe them). +2. Keep the same brand identity and overall strategy. + +3. Freshen: new headline variations, new background colors, new angles that weren't tested. +4. Do NOT change what's working — if the user says "these are doing fine, just want fresh versions," keep the structure and vary the copy/colors. + +## Iterating from Performance Data + +When the user provides performance data: + +1. **Analyze winners**: Identify winning themes, structures, word patterns, and character utilization in top performers (by CTR, conversion rate, or ROAS). +2. **Analyze losers**: Identify themes that fall flat and common patterns in underperformers. + +3. **Generate new variations**: Double down on winning themes, extend winning angles, test 1-2 new unexplored angles, avoid patterns from underperformers. +4. **Document the iteration**: Track what was learned, what's being tested, and what angles were retired. + +Present the analysis to the user before building new ads: + +```text + +## Performance Analysis + +### Winners (keep and extend) + +- Pain point angles performing 2.3x above average CTR +- Headlines with specific numbers ("75% faster") outperform vague claims + +### Losers (retire) + +- Curiosity angles underperforming — audience is solution-aware, not problem-aware +- Long headlines (over 25 chars) getting truncated on mobile + +### New Test Plan + +- 2 new pain point variations (doubling down on winner) +- 1 social proof angle (untested category) + +- Retire all curiosity angles + +``` + +## Research Before Writing + +Use web search to find examples of top-performing ads in the user's vertical. Search for ad breakdowns, swipe files, and case studies — e.g. `[industry] top performing Facebook ads 2026`or`[industry] TikTok ad examples`. Reverse-engineer: what hook, what angle, what visual pattern. Don't guess what works — look it up. + +## Common Mistakes + +### Content overload (most common) + +- Adding icons, stats rows, feature grids, or badges — these violate the under-20-word rule. Each ad should have exactly 4 elements: Logo, Hero, Benefit, CTA. +- Using gradients instead of flat solid colors (except awareness/launch hero images) + +- Centering all content instead of left-aligning (left-aligned text feels more intentional and professional) + +#### Logo issues + +- Using plain text instead of the brand's actual logo — always extract the real SVG from the brand's website first +- Truncated SVG path data — always verify path length and max coordinates after extraction + +- Not checking that the SVG viewBox contains the full logo (max X/Y must be within viewBox bounds) + +##### Brand identity + +- Trusting web search for brand colors — always extract actual hex values from the site's CSS +- Using generic fonts (e.g., Inter) instead of the brand's actual typeface + +- Not loading fonts via Google Fonts link in the HTML head — relying on system fonts + +###### Technical + +- width Xvw with height auto alone on square logo images (overflows container) +- Forgetting chmod 644 on assets copied from attached_assets (server can't read them) + +- Not incrementing ?v=N on iframe URLs after editing HTML files +- Placing ad files in the wrong directory (use artifacts/mockup-sandbox/public/ads/, not client/public/ads/) + +###### Copy + +- RSA headlines that only work in sequence (Google mixes them — each must stand alone) +- Writing for the 125-char feed limit when Reels only shows 72 + +- All angles being the same message reworded (vary the psychology, not the synonyms) +- Text in the bottom 35% of a 9:16 ad (covered by platform UI) + +- Letting Performance Max auto-generate video — always supply your own + +###### Subagent delegation + +- Not including the full HTML structure template in the subagent task — subagents will invent their own layout +- Not repeating the golden rules in each subagent task — they don't inherit context from the main agent + +- Not specifying font loading instructions — subagents will use system fonts +- Not providing the exact brand colors and logo SVG — subagents will guess diff --git a/.local/secondary_skills/ai-recruiter/.fingerprint b/.local/secondary_skills/ai-recruiter/.fingerprint new file mode 100644 index 0000000..60d50b0 --- /dev/null +++ b/.local/secondary_skills/ai-recruiter/.fingerprint @@ -0,0 +1 @@ +9b789b8fdda650cb7e419876d5e94b45 \ No newline at end of file diff --git a/.local/secondary_skills/ai-recruiter/SKILL.md b/.local/secondary_skills/ai-recruiter/SKILL.md new file mode 100644 index 0000000..96e1a09 --- /dev/null +++ b/.local/secondary_skills/ai-recruiter/SKILL.md @@ -0,0 +1,1087 @@ +--- +name: ai-recruiter +description: Source and evaluate candidates with job analysis, CV screening, and pipeline tracking. +--- + +# AI Recruiter + +Help source and evaluate candidates for open roles. Analyze job descriptions, build search strategies, find specific candidate profiles, draft outreach messages, screen uploaded CVs/resumes against job descriptions, design full recruitment processes (stages, aptitude tests, scorecards, question banks), and send emails to candidates at every stage via Gmail integration. + +## When to Use + +### Hiring & sourcing strategy + +- User needs to hire for a role and wants sourcing strategy +- User wants to find specific candidate profiles for a role + +- User asks about the talent landscape or market for a role +- User wants to know who to source from or which competitors to target + +- User asks where to find candidates beyond LinkedIn (GitHub, conferences, HN, etc.) +- User wants to search for engineers/designers/PMs on GitHub, Stack Overflow, or other platforms + +#### Job descriptions & postings + +- User wants to improve, review, or optimize a job description +- User asks if their job posting is biased or wants it checked for inclusive language + +- User wants to understand why they're not getting enough applicants + +##### CV/resume screening & candidate evaluation + +- User uploads CVs/resumes and wants them screened against a job description +- User wants candidate evaluation criteria + +- User wants to compare two or more candidates side-by-side +- User asks who to advance, hold, or reject from a candidate pool + +- User wants candidates ranked from strongest to weakest + +###### Interview process & assessment design + +- User needs interview questions for a specific role +- User wants to design a full recruitment process (stages, questions, tests, scorecards, timelines) + +- User wants to create a scorecard or evaluation rubric for interviews +- User wants to design a take-home assignment, coding challenge, or skills test + +- User asks what to look for in a portfolio review or case study presentation +- User asks about ideal interview-to-offer timelines or how to reduce candidate drop-off + +###### Outreach & candidate communication + +- User wants to send emails (confirmation, rejection, next steps) to candidates +- User wants to write cold outreach messages to passive candidates + +- User asks how to get better response rates on outreach +- User wants to draft a follow-up for a candidate who hasn't replied + +- User wants to send offer letters, rejection emails, or hold/waitlist notifications + +###### Compensation & market intelligence + +- User asks what companies are paying for a specific role +- User wants comp benchmarks for salary negotiation or offer planning + +###### Pipeline tracking & scheduling + +- User wants to track candidates in a shared pipeline (Google Sheets) +- User wants to add candidates to a tracking spreadsheet or update their status + +- User wants to schedule interviews (Google Calendar) +- User wants to put an interview on their calendar or check interviewer availability + +###### Follow-ups & reminders + +- User needs follow-up reminders for candidate actions +- User wants to set a reminder to collect interview feedback from the team + +- User wants to be reminded to follow up with a candidate after a set period + +###### Hiring metrics & process improvement + +- User asks how long it should take to fill a role +- User wants to know what metrics to track for their hiring process + +- User asks about hiring funnel conversion rates or benchmarks + +## When NOT to Use + +- Sales prospecting (use find-customers skill) +- General market research (use deep-research skill) + +- Writing job-related content (use content-machine skill) + +## Proactive Email Communication — Always Offer This + +At every key decision point in the recruiting workflow, proactively inform the user that you can draft and send emails on their behalf via Gmail. Do not wait for them to ask — surface this capability yourself. + +### When to offer email drafting and sending + +- After completing CV screening — offer to send advancement, rejection, or hold emails to each candidate +- After sourcing candidates — offer to draft and send cold outreach emails + +- When the user discusses interview scheduling — offer to send interview invitation emails with logistics +- When the user makes a hiring decision — offer to send congratulations/offer emails or final rejection emails + +- At any stage transition — offer to send process update emails to keep candidates informed + +#### How to offer it + +When presenting results (e.g., after screening CVs), always include a line like: + +> "I can also draft and send personalized emails to each candidate — advancement confirmations, rejections, or interview invitations — directly from your Gmail. Want me to prepare those?" + +##### Types of emails you can send + +| Email Type | When to Offer | + +|------------|--------------| + +| **Cold outreach** | After sourcing candidates (Step 6) | + +| **Application received** | When a user mentions receiving applications | + +| **Advancement / next steps** | After CV screening recommends advancing a candidate | + +| **Interview invitation** | When scheduling interviews — include date, time, format, interviewer names | + +| **Interview follow-up** | After interviews — thank the candidate, outline next steps and timeline | + +| **Rejection** | After CV screening or interview rounds — respectful, brief, no detailed feedback | + +| **Hold / waitlist** | When a candidate is strong but timing isn't right | + +| **Offer / congratulations** | When a hiring decision is made | + +| **Process update** | When there are delays or timeline changes — keep candidates in the loop | + +| **Reference request** | When moving to reference checks — polite request to the candidate or referee | + +**Gmail setup:** If the user agrees to send emails and Gmail is not yet connected, immediately guide them through the Gmail integration setup (see Step 8 for details). Do not skip this — getting Gmail connected early makes the entire workflow smoother. + +###### Also proactively offer these integration-powered capabilities + +- **"Want me to set up a shared tracking sheet for this role?"** — Google Sheets pipeline tracker (see Step 11). Offer at the start of any hiring process or after CV screening. +- **"I can schedule interviews directly on your calendar."** — Google Calendar integration (see Step 12). Offer when advancing candidates to interview stages. + +- **"Should I set a follow-up reminder for this?"** — Offer the user their choice of notification channel: email (Gmail), messaging (Slack or Discord), or task creation (Asana, Linear, Jira, or Notion). See Step 13. Ask the user once which channel they prefer, then use it consistently. + +## Workflow — Follow This Order + +### Step 0: Research First, Then Ask Questions + +Before producing any output, always do two things in this order: + +#### 0a. Search for the role and company + +If the user names a company or role, use `webSearch` to find: + +- The actual job posting (check Ashby, Lever, Greenhouse, the company careers page) +- Latest company details: funding, valuation, headcount, ARR, recent news + +- Competitor landscape for the role + +This gives you the context to ask smart questions instead of generic ones. + +##### 0b. Ask the user clarifying questions + +Do not assume details. Ask about: + +- Which specific role (if the company has multiple open positions, list them as choices) +- Seniority level + +- Location / remote policy +- What candidate background matters most (domain-specific vs. open to adjacent backgrounds) + +- Whether competitors are fair game for sourcing +- Any specific gaps on the team they're trying to fill (e.g., growth, technical, enterprise, design) + +- Any other preferences (e.g., founder background, specific skills) + +Only proceed to output after you have answers. + +### Step 1: Calibrate the Role + +Split requirements into three buckets — be ruthless, most JDs list nice-to-haves as must-haves and shrink the pool 80%: + +- **Must-have** (3-4 max): Deal-breakers. Can't do the job without these on day one. +- **Learnable in 90 days**: Most "required" skills belong here. + +- **Pedigree signals**: School, FAANG experience, etc. — these filter for bias, not ability. Drop them unless there's a specific reason. + +**Comp research:** `webSearch: "levels.fyi [role] [company tier]"`or`"[role] salary [city] site:glassdoor.com"`. For startups,`webSearch: "Pave [role] equity benchmarks"`. Keep comp in the internal strategy doc for reference but do NOT include it in outreach templates by default. + +### Step 2: Build Boolean Search Strings + +Boolean-savvy recruiters fill roles ~23% faster (LinkedIn 2023 data). LinkedIn Recruiter caps each field at ~300 chars — split across Title and Keywords rather than cramming one field. + +#### Core pattern — put role in Title, skills in Keywords + +```text + +Title: ("staff engineer" OR "senior engineer" OR "tech lead" OR "principal") + +Keywords: (Rust OR Go OR "distributed systems") AND (Kubernetes OR k8s) NOT (manager OR director OR intern) + +``` + +**Synonym rings — the \#1 missed tactic.** Titles fragment massively across companies: + +```text + +("product manager" OR "product owner" OR "PM" OR "program manager" OR "product lead") + +("data scientist" OR "ML engineer" OR "machine learning engineer" OR "applied scientist" OR "research scientist") + +("SRE" OR "site reliability" OR "devops engineer" OR "platform engineer" OR "infrastructure engineer") + +``` + +**Impact-verb trick** — surface doers, not title-holders: + +```text + +("built" OR "shipped" OR "launched" OR "scaled" OR "led migration" OR "0 to 1") + +``` + +##### X-ray search (Google, bypasses LinkedIn limits) + +```text + +site:linkedin.com/in ("staff engineer" OR "principal engineer") "rust" "san francisco" -recruiter -hiring + +``` + +### Step 3: Provide Direct LinkedIn Search Links + +Always generate at least 5 clickable LinkedIn search URLs that the user can open directly in their browser. These should be pre-built with URL-encoded keywords, location filters, and relevant company/skill terms. + +#### URL format + +```text + +https://www.linkedin.com/search/results/people/?keywords=URL_ENCODED_KEYWORDS&geoUrn=%5B%22GEO_ID%22%5D&origin=FACETED_SEARCH + +``` + +##### Common geo IDs + +- SF Bay Area: `102095887` +- New York: `103644278` + +- US: `103644278` +- London: `90009496` + +Create separate links for different search angles: + +1. Candidates at direct competitors +2. Candidates with the specific skill/background the user prioritized + +3. Candidates at adjacent companies in the space +4. Candidates at tier 2/3 companies (bigger pool) + +5. Broader keyword search for passive candidates + +### Step 4: Find Specific Candidate Profiles + +Always use `webSearch`with`site:linkedin.com/in` queries to find specific named candidates. Search multiple angles: + +- PMs/engineers at competitor companies +- People with the specific background the user asked for (e.g., founder experience, UI expertise) + +- People at adjacent companies in the same space + +Present candidates in a table with: + +- Name +- Current role + +- Why they fit (1 sentence) +- Hyperlinked LinkedIn profile URL + +Aim for 10-15 specific profiles, organized into tiers (e.g., direct competitors, adjacent companies, broader pool). + +### Step 5: Source Beyond LinkedIn + +LinkedIn InMail response rates have dropped from 30%+ to 10-13% over 5 years as the platform saturated. Diversify: + +| Channel | Best for | Tactic | + +|---------|----------|--------| + +| **GitHub** | Engineers | `webFetch` their profile — check contribution graph (consistent > spiky), pinned repos, languages bar, PR review quality on public projects. | + +| **GitHub Search** | Niche skills | `site:github.com "location: [city]" language:Rust` or search commits/issues in relevant OSS projects | + +| **Stack Overflow** | Deep specialists | Top answerers on niche tags — check profile for contact info | + +| **Conference talks** | Senior/staff+ | `webSearch: "[conference name] speakers 2025"` — speakers are pre-vetted for communication skills | + +| **Papers/Google Scholar** | ML/research | Co-authors on relevant papers, often with .edu emails | + +| **HN "Who wants to be hired"** | Startup-minded | Monthly thread, candidates self-describe, `site:news.ycombinator.com "who wants to be hired"` | + +| **Product Hunt** | Builder-types | Makers of top products in the relevant category | + +| **Twitter/X** | Thought leaders | Search for people posting about the relevant domain | + +| **YC Alumni** | Founder-PMs | Founders whose startups ended and moved into PM/leadership roles | + +| **Paid aggregators** | Volume | SeekOut, HireEZ (45+ platforms), Gem, Juicebox/PeopleGPT | + +### Step 6: Outreach That Gets Replies + +**2025 benchmarks:** Cold InMail averages 10-13% response. Personalized outreach with a specific hook hits 20%+. 86% of candidates ignore generic messages entirely (TalentBoard 2024). + +#### Structure — 4 sentences max + +1. **Hook** (why *them*, specifically): "Saw your PR on the Tokio scheduler — the approach to work-stealing was clean." +2. **Why this role matters** (to them, not to you): "We're 12 engineers, pre-Series-B, and the entire storage layer is unowned." + +3. **One concrete detail**: Remote policy, a tech problem they'd find interesting, team size, or growth metrics. Avoid listing comp — save that for when they respond. +4. **Low-friction CTA**: "Worth 15 min to hear more?" — not "Let me know if you're open to opportunities." + +**Do NOT include compensation in outreach templates.** Comp details belong in the internal strategy section. If a candidate responds, share comp on the first call. Leading with comp in cold outreach can anchor low or signal desperation. + +**Subject lines:** Use their project name or the specific tech, not "Opportunity at [Company]." Lowercase, short, looks like a peer wrote it. + +**Follow-up:** One bump at day 5 with a *new* piece of info (funding news, a blog post, the hiring manager's name). Never "just following up." + +**Generate 3 outreach templates** tailored to different candidate segments (e.g., competitors, adjacent companies, career-changers). Customize the angle for each. + +### Step 7: CV/Resume Screening + +When the user uploads CVs/resumes and provides a job description, evaluate each candidate systematically. + +#### For each CV, assess + +1. **Must-have match** — Does the candidate meet the must-have requirements from Step 1? Score each as Met / Partial / Not Met. +2. **Experience relevance** — How closely does their work history align with the role? Look for domain experience, comparable company stage, and scope of responsibility. + +3. **Skills match** — Technical and soft skills alignment with the JD. Distinguish between demonstrated skills (backed by examples) and claimed skills (just listed). +4. **Career trajectory** — Are they on an upward path? Look for progression in title, scope, or impact. Lateral moves into the role's domain are a positive signal. + +5. **Red flags** — Unexplained gaps, frequent short stints (< 1 year at multiple companies), title inflation without substance, or misalignment between stated role and described responsibilities. +6. **Standout factors** — Anything that makes them notably strong: open-source contributions, published work, relevant side projects, public speaking, or domain-specific achievements. + +##### Output per candidate + +| Field | Details | + +|-------|---------| + +| **Name** | Full name from CV | + +| **Current/Last Role** | Title @ Company | + +| **Overall Fit** | Strong Fit / Partial Fit / Weak Fit | + +| **Must-Have Score** | X/Y met | + +| **Key Strengths** | 2-3 bullet points | + +| **Key Gaps** | 1-2 bullet points | + +| **Recommendation** | Advance to interview / Hold / Reject | + +| **Notes** | Any context (e.g., "strong technical but no leadership experience yet") | + +###### After screening all candidates + +- Rank candidates from strongest to weakest fit +- Provide a summary comparison table + +- Recommend which candidates to advance, hold, or reject +- If the user wants, draft personalized emails for each decision (see Step 8) + +### Step 8: Send Candidate Emails via Gmail + +When the user wants to communicate decisions to candidates (confirmations, rejections, next steps, interview invitations), use the Gmail integration to send emails directly. + +#### Prerequisites + +- The Gmail integration must be connected. Use `searchIntegrations("gmail")` to check availability. +- If not connected, guide the user through setup: use `proposeIntegration`with the Gmail connector ID to trigger OAuth. After the user authorizes, use`addIntegration`to wire it to the project, then`proposeIntegration` again to establish the token. + +- Use `listConnections('google-mail')` to get credentials once connected. + +##### Email workflow + +1. **Draft first, send second.** Always show the user the email content before sending. Use `confirm_connector_operation` to get explicit approval before each send. +2. **Personalize every email.** Reference the candidate's name, the specific role, and at least one detail from their CV (e.g., "your experience leading the migration at Acme Corp"). + +3. **Match tone to decision:** + +- **Advancing:** Warm, specific about why they stood out, clear next steps with timeline +- **Rejection:** Respectful, brief, encouraging. Thank them for their time. Do NOT give detailed feedback on why they were rejected (legal risk). Keep it to 3-4 sentences. + +- **Hold/Waitlist:** Honest about timeline, express genuine interest, set expectations for when they'll hear back + +###### Email templates by type + +###### Advancing to interview + +- Subject: `Next steps — [Role Title] at [Company]` +- Body: Thank them, mention 1 specific thing from their background, explain the next step (phone screen / technical / panel), propose 2-3 time slots or link to scheduling tool, sign off warmly + +###### Rejection + +- Subject: `Update on your application — [Company]` +- Body: Thank them for applying, note the role was competitive, wish them well, 3-4 sentences max. No detailed feedback unless the user explicitly requests it. + +###### Hold/Waitlist + +- Subject: `Update on [Role Title] — [Company]` +- Body: Thank them, explain the timeline honestly, express continued interest, set expectation for next contact + +###### Sending via Gmail integration + +```javascript + +const conns = await listConnections('google-mail'); + +if (conns.length === 0) { + +// No Gmail connection — guide user through setup + +const results = await searchIntegrations("gmail"); + +// Use proposeIntegration with the connector ID + +} + +const settings = conns[0].settings; + +// Use the Gmail API to send emails + +// Always use confirm_connector_operation before sending + +``` + +###### Rules + +- Never send emails without explicit user approval via `confirm_connector_operation` +- Always show the draft to the user first and let them edit if needed + +- Send one email at a time, confirming each with the user (unless they explicitly approve batch sending) +- Include the user's name/signature in the from field, not the AI's + +- Log all sent emails (recipient, subject, timestamp, decision type) for the user's records + +### Step 9: Suggested Interview Questions + +Include a short section of suggested interview questions at the bottom of the output. Use behavioral questions (STAR format) over hypothetical ones. Organize by the key criteria identified in Step 1. + +Keep it lightweight — 2 questions per criterion, 3-4 criteria max. No scoring rubrics or evaluation matrices unless the user specifically asks for one. + +### Step 10: Design a Full Recruitment Process + +When the user asks to design a recruitment process, build a complete end-to-end hiring pipeline tailored to the specific role, company size, and seniority level. Use `webSearch` to research current best practices for the role type (e.g., "best interview process for senior backend engineer 2025"). + +#### Always ask the user first + +- How many stages do they want? (Lean startups may want 3; enterprises may need 5-6) +- Any existing process they want to improve or replace? + +- Time constraint — how fast do they need to hire? +- Who is available to participate as interviewers? + +- Any specific skills or traits they want to test heavily? + +##### Process design output — include all of the following + +#### 1. Process Overview & Timeline + +A visual stage-by-stage pipeline with estimated duration for each stage and total time-to-hire target. + +| Stage | Duration | Owner | Pass Rate | + +|-------|----------|-------|-----------| + +| Application / CV Screen | 1-2 days | Recruiter / AI | ~20-30% advance | + +| Phone Screen | 30 min | Recruiter / Hiring Manager | ~50% advance | + +| Aptitude / Skills Test | 2-3 days (take-home) or 1 hour (live) | Candidate | ~40-60% advance | + +| Technical / Domain Interview | 60 min | Team members | ~50% advance | + +| Culture / Values Interview | 45 min | Cross-functional | ~70% advance | + +| Final / Hiring Manager Interview | 45 min | Hiring Manager | ~80% advance | + +| Reference Checks | 2-3 days | Recruiter | ~90% advance | + +| Offer | 1-2 days | Hiring Manager + HR | — | + +Adjust the number and type of stages based on the role. Junior roles may skip the take-home; senior/leadership roles may add a presentation or case study stage. + +#### 2. Aptitude & Skills Tests + +Design role-specific assessments. These should be practical, time-boxed, and relevant to actual job tasks — never trivia or gotcha questions. + +##### By role type + +| Role Type | Test Format | Duration | What It Measures | + +|-----------|------------|----------|-----------------| + +| **Engineering** | Take-home coding challenge OR live pair programming | 2-3 hrs (take-home) or 60 min (live) | Code quality, problem-solving, system design thinking | + +| **Product Management** | Product case study (written or presented) | 2 hrs (take-home) or 45 min (live) | Prioritization, user empathy, analytical thinking, communication | + +| **Design** | Design challenge with constraints | 3-4 hrs (take-home) or 60 min (live whiteboard) | Visual thinking, UX reasoning, craft quality | + +| **Data Science / ML** | Data analysis challenge with real dataset | 2-3 hrs | Statistical reasoning, tool proficiency, communication of findings | + +| **Sales / BD** | Mock sales pitch or objection-handling roleplay | 30-45 min (live) | Persuasion, product knowledge, listening skills | + +| **Marketing** | Campaign brief or content strategy exercise | 2 hrs (take-home) | Strategic thinking, creativity, channel knowledge | + +| **Operations** | Process improvement case study | 1-2 hrs | Systems thinking, prioritization, attention to detail | + +| **Leadership / Management** | Leadership scenario or team-building exercise | 45 min (live) | Decision-making, conflict resolution, delegation | + +###### Test design principles + +- Mirror real work the candidate would do in the role — not abstract puzzles +- Time-box strictly — respect the candidate's time. Max 3 hours for take-homes + +- Provide clear evaluation criteria to assessors before they review submissions +- Offer alternative formats when possible (e.g., "bring your own project" as an option alongside a take-home) + +- For take-homes, always give at least 5 days to complete (candidates have jobs) + +**Include a sample test for the specific role** with: + +- The prompt / instructions candidates receive +- Evaluation rubric (what good, average, and poor looks like) + +- Time limit +- Submission format + +#### 3. Interview Question Bank + +For each interview stage, provide a structured question set. Organize by competency area. + +##### Format per stage + +###### [Stage Name] — [Interviewer Role] + +| Competency | Question | What to Listen For | Red Flag | + +|------------|----------|-------------------|----------| + +| [e.g., Problem Solving] | "Tell me about a time you had to solve a problem with incomplete information." | Structured approach, comfort with ambiguity, outcome focus | Waited for perfect info, blamed others, no clear outcome | + +| [e.g., Collaboration] | "Describe a project where you had to work with a difficult stakeholder." | Empathy, communication strategy, resolution | Avoided the person, escalated immediately, us-vs-them framing | + +Provide 3-4 questions per stage, covering different competencies. Include the "What to Listen For" and "Red Flag" columns so interviewers know what good and bad answers look like without needing training. + +#### 4. Evaluation Scorecards + +For each interview stage, provide a simple scorecard interviewers fill out immediately after the interview. + +##### Scorecard format + +```text + +Candidate: _______________ + +Interviewer: _______________ + +Stage: _______________ + +Date: _______________ + +| Criteria | 1 (Below) | 2 (Meets) | 3 (Exceeds) | Score | Notes | + +|----------|-----------|-----------|-------------|-------|-------| + +| [Criterion 1] | [what "below" looks like] | [what "meets" looks like] | [what "exceeds" looks like] | ___ | ___ | + +| [Criterion 2] | ... | ... | ... | ___ | ___ | + +| [Criterion 3] | ... | ... | ... | ___ | ___ | + +Overall recommendation: [ ] Strong Advance [ ] Advance [ ] Hold [ ] Reject + +Key observations (2-3 sentences): + +``` + +Keep it to 3-5 criteria per scorecard. Interviewers should complete it within 5 minutes of the interview ending — before discussing with other interviewers (prevents anchoring bias). + +#### 5. Candidate Communication Plan + +Map out every touchpoint with the candidate throughout the process. For each, note the timing, channel, and purpose. Offer to draft and send each of these via Gmail (see Step 8). + +| Touchpoint | Timing | Channel | Purpose | + +|------------|--------|---------|---------| + +| Application received | Within 24 hours | Email | Confirm receipt, set expectations for timeline | + +| Phone screen invite | Within 3 days of application | Email | Schedule the call | + +| Post-phone-screen update | Within 24 hours | Email | Advance or reject | + +| Test/assignment sent | Same day as advancement | Email | Instructions, deadline, support contact | + +| Interview invite | Within 2 days of test review | Email | Schedule, prep materials, interviewer names | + +| Post-interview update | Within 48 hours | Email | Advance, hold, or reject | + +| Offer | Within 24 hours of final decision | Phone call + email | Verbal first, written follow-up | + +| Rejection (final round) | Within 48 hours | Email or phone | Respectful, brief, encouraging | + +#### 6. Process Metrics & Targets + +Define what success looks like for the hiring process itself: + +| Metric | Target | How to Measure | + +|--------|--------|---------------| + +| Time-to-fill | [role-appropriate target] | Days from posting to accepted offer | + +| Candidate experience score | 4+/5 | Post-process survey (send to all candidates, including rejected) | + +| Offer acceptance rate | >80% | Offers accepted / offers extended | + +| Stage drop-off | <20% per stage | Candidates who withdraw at each stage | + +| Interviewer calibration | <1 point spread | Variance in scorecard ratings across interviewers for same candidate | + +| Diversity of pipeline | [user-defined target] | Demographics at each funnel stage | + +### Step 11: Candidate Pipeline Tracking via Google Sheets + +Use Google Sheets as the central tracking system for the entire hiring pipeline. This is where candidate data, evaluations, and stage history live — accessible to the full hiring team. + +#### Prerequisites (2) + +- Google Sheets integration must be connected. Use `searchIntegrations("google sheets")` to check availability. +- If not connected, guide the user through setup: use `proposeIntegration`with connector ID`connector:ccfg_google-sheet_E42A9F6CA62546F68A1FECA0E8`. + +- Use `listConnections('google-sheet')` to get credentials once connected. + +##### When to create a tracking sheet + +- At the start of any hiring process — offer to set one up immediately +- After CV screening — populate it with all screened candidates and their evaluations + +- Whenever the user mentions wanting to track or share candidate status with their team + +###### Sheet structure — create one spreadsheet per role with these tabs + +###### Tab 1: Pipeline Overview + +| Column | Description | + +|--------|------------| + +| Candidate Name | Full name | + +| Email | Contact email | + +| Current Stage | Application / Phone Screen / Test / Interview / Offer / Rejected / Hired | + +| Stage Entry Date | When they entered the current stage | + +| Days in Stage | Auto-calculated | + +| Overall Rating | Strong / Partial / Weak (from CV screening or interviews) | + +| Next Action | What needs to happen next | + +| Next Action Due | Date the next action is due | + +| Assigned To | Who owns the next action | + +| Notes | Free-form notes | + +###### Tab 2: Candidate Evaluations + +Running evaluation that compounds insights as candidates progress. Update this after each stage. + +| Column | Description | + +|--------|------------| + +| Candidate Name | Full name | + +| CV Screen Score | Must-have score (X/Y) and overall fit | + +| CV Screen Notes | Key strengths, gaps, and red flags from initial screening | + +| Phone Screen Score | 1-3 rating | + +| Phone Screen Notes | Interviewer observations | + +| Test Score | Assessment results and rubric scores | + +| Test Notes | Evaluator comments | + +| Interview 1 Score | Scorecard results | + +| Interview 1 Notes | Key observations | + +| Interview 2 Score | Scorecard results | + +| Interview 2 Notes | Key observations | + +| Final Recommendation | Hire / Strong Hold / Reject | + +| Comparative Notes | How this candidate compares to others in the pipeline | + +###### Tab 3: Communication Log + +| Column | Description | + +|--------|------------| + +| Date | When the email was sent | + +| Candidate | Recipient name | + +| Email Type | Outreach / Confirmation / Interview Invite / Rejection / Offer / Follow-up | + +| Subject Line | Email subject | + +| Status | Sent / Opened / Replied (if tracking available) | + +| Follow-up Due | When to follow up if no response | + +###### Tab 4: Funnel Metrics + +| Column | Description | + +|--------|------------| + +| Stage | Pipeline stage name | + +| Entered | Count of candidates who entered this stage | + +| Advanced | Count who moved to the next stage | + +| Rejected | Count who were rejected at this stage | + +| Withdrew | Count who dropped out | + +| Conversion Rate | Advanced / Entered | + +| Avg Days in Stage | Average time spent in this stage | + +###### Keeping the sheet updated + +- After every action (CV screen, email sent, interview completed, decision made), offer to update the tracking sheet +- When the user shares interview feedback, update the evaluation tab and comparative notes + +- At regular intervals, offer to generate a funnel report from the metrics tab + +```javascript + +const conns = await listConnections('google-sheet'); + +if (conns.length === 0) { + +const results = await searchIntegrations("google sheets"); + +// Use proposeIntegration with the connector ID + +} + +const settings = conns[0].settings; + +// Use the Google Sheets API to create and update the tracking spreadsheet + +// Always use confirm_connector_operation before write operations + +``` + +### Step 12: Interview Scheduling via Google Calendar + +Use Google Calendar to schedule interviews directly, rather than just proposing times via email. This eliminates back-and-forth and ensures calendar conflicts are checked. + +#### Prerequisites (3) + +- Google Calendar integration must be connected. Use `searchIntegrations("google calendar")` to check availability. +- If not connected, guide the user through setup: use `proposeIntegration`with connector ID`connector:ccfg_google-calendar_DDDBAC03DE404369B74F32E78D`. + +- Use `listConnections('google-calendar')` to get credentials once connected. + +##### When to offer calendar scheduling + +- When advancing a candidate to an interview stage +- When the user mentions needing to schedule a call or meeting with a candidate + +- During process design, when mapping out the communication plan + +###### Scheduling workflow + +1. **Check interviewer availability** — Query the calendar for free/busy times for the relevant interviewers +2. **Propose time slots** — Present 3-5 available slots to the user for approval + +3. **Create the calendar event** — Include: + +- Title: `[Interview Type] — [Candidate Name] for [Role Title]` +- Duration: Based on the stage (30 min phone screen, 60 min technical, 45 min culture fit) + +- Attendees: Interviewer(s) + candidate email (if available) +- Description: Include the candidate's CV summary, the questions/scorecard for this stage, and any prep notes + +- Video link: If the user uses Google Meet, include a Meet link automatically + +1. **Send interview invitation email** — Via Gmail, send the candidate a personalized invite with the confirmed time, format (video/phone/in-person), interviewer name(s), and any prep materials +2. **Set a follow-up reminder** — Create a calendar event for the interviewer 24 hours after the interview titled `[ACTION] Submit scorecard — [Candidate Name]` to prompt timely feedback + +```javascript + +const conns = await listConnections('google-calendar'); + +if (conns.length === 0) { + +const results = await searchIntegrations("google calendar"); + +// Use proposeIntegration with the connector ID + +} + +const settings = conns[0].settings; + +// Use the Google Calendar API to check availability and create events + +// Always use confirm_connector_operation before creating events + +``` + +### Step 13: Follow-Up Reminders + +When the user opts in to follow-up reminders, offer three categories of delivery channels — let them choose their preferred method (or combine multiple). + +**At the start of any hiring workflow, ask:** "Would you like me to send you follow-up reminders as we go through this process? I can notify you via email, Slack, Discord, or create tasks in Asana, Linear, Jira, or Notion — whichever you already use." + +Once the user opts in and chooses a channel, use it consistently for all reminders without asking again each time. + +#### Option A: Email notifications via Gmail + +- Send an email from the user's Gmail to themselves +- Subject: `[Hiring Reminder] [Action needed] — [Candidate Name] for [Role]` + +- Body: Full context — what happened, what to do next, a link to the tracking sheet, and any deadlines +- Examples: + +- `[Hiring Reminder] Send follow-up to Sarah Chen — no response after 5 days` +- `[Hiring Reminder] Collect interview feedback from team — Alex Rivera` + +- `[Hiring Reminder] Send offer letter to Jordan Park — deadline: Friday` + +##### Option B: Messaging app notifications (Slack or Discord) + +Send a message to the user via their preferred messaging platform. Ideal for teams who want real-time visibility. + +- Use a consistent, scannable format: + +```text + +*Hiring Reminder* + +*Candidate:* Sarah Chen + +*Role:* Senior Backend Engineer + +*Action needed:* Send follow-up email — no response after 5 days + +*Due:* Today + +*Context:* Initial outreach sent on March 20. No reply yet. Suggested: bump with new info (recent funding announcement). + +*Tracking sheet:* [link] + +``` + +- Can post to a shared channel (e.g., `#hiring`) so the whole team sees what needs attention, or send as a DM to the specific person responsible +- Ask the user which channel/server to post to on first setup + +| Platform | Connector ID | Connection Name | + +|----------|-------------|-----------------| + +| **Slack** | `connector:ccfg_slack_01KH7W1T1D6TGP3BJGNQ2N9PEH`|`slack` | + +| **Discord** | `connector:ccfg_discord_72DFF975D4C5460D83A3A5FD12`|`discord` | + +###### Option C: Task/project management app notifications (Asana, Linear, Jira, or Notion) + +Create tasks or items in the user's project management tool, so follow-ups appear alongside their other work. Each follow-up becomes a trackable task with a due date and assignee. + +- **Asana** — Create a task in a designated hiring project. Set the due date, assignee, and description with full context. +- **Linear** — Create an issue in a hiring project. Tag it with a label like `hiring`or`recruiting`. Set priority and assignee. + +- **Jira** — Create a ticket in a hiring board. Set the due date, assignee, and description. +- **Notion** — Add an entry to a hiring database page. Include candidate name, action needed, due date, and context. + +Task format (adapt to the platform): + +- **Title:** `[FOLLOW-UP] [Action needed] — [Candidate Name]` +- **Description:** Full context — what happened, what to do, deadline, link to tracking sheet + +- **Due date:** The follow-up date +- **Assignee:** The person responsible (ask the user on first setup) + +| Platform | Connector ID | Connection Name | + +|----------|-------------|-----------------| + +| **Asana** | `connector:ccfg_asana_17D6AEDD454A41BA8870C2542E`|`asana` | + +| **Linear** | `connector:ccfg_linear_01K4B3DCSR7JEAJK400V1HTJAK`|`linear` | + +| **Jira** | `connector:ccfg_jira_8D0B4B1730F64429A4FC3ACB88`|`jira` | + +| **Notion** | `connector:ccfg_notion_01K49R392Z3CSNMXCPWSV67AF4`|`notion` | + +###### Setup for any notification channel + +1. Use `searchIntegrations("[platform name]")` to check availability +2. If not connected, guide the user through setup with `proposeIntegration` using the connector ID from the table above + +3. Use `listConnections('[connection name]')` to get credentials once connected +4. Ask the user where to send notifications (channel, project, board, or database) + +5. Always use `confirm_connector_operation` before creating tasks or sending messages + +```javascript + +// Example for any platform — adapt the connection name + +const conns = await listConnections('[connection-name]'); + +if (conns.length === 0) { + +const results = await searchIntegrations("[platform name]"); + +// Use proposeIntegration with the connector ID + +} + +const settings = conns[0].settings; + +// Use the platform's API to send messages or create tasks + +// Always use confirm_connector_operation before write operations + +``` + +###### When to create reminders + +- After sending any candidate email — set a follow-up for 5 business days if no response +- After an interview — remind the interviewer to submit their scorecard within 24 hours + +- After advancing a candidate — remind to schedule the next stage within 2-3 business days +- After making an offer — remind to check for acceptance within the deadline + +- After placing a candidate on hold — remind to re-engage after the specified waiting period +- After receiving a CV/application — remind to review within 1-2 business days + +## Hiring Benchmarks + +- **Time-to-fill**: 44 days US average (SHRM 2025); tech roles run longer +- **Cost-per-hire**: $6-7k standard tech roles; $12k+ for ML/security/staff+ (Deloitte 2024) + +- **Funnel**: Tech roles see ~110 applicants/opening, ~5% get interviews +- **Speed matters**: Top candidates are off-market in 10 days. The interview-to-offer stage is where most teams lose — compressing it cuts time-to-hire by ~26%. + +- **LinkedIn Recruiter cost**: $1.6k/yr (Lite) to $10.8k+/yr (Corporate, 150+ InMails/mo) + +## Bias Reduction + +- Strip unnecessary degree requirements — they filter for socioeconomic background, not skill +- Run JD through `webSearch: "gender decoder job description"` tools — "rockstar," "ninja," "aggressive" skew male applicant pools + +- Same questions, same order for every candidate +- Score immediately after each interview, before discussing with other interviewers (anchoring bias) + +- Source from non-traditional channels (HN, PH, YC alumni, blogs) to avoid LinkedIn-only pool bias + +## Output Structure + +The final deliverable should follow this order. Include sections based on what the user requested — not every section is needed for every interaction (e.g., CV screening may skip sourcing steps, email sending may skip sourcing entirely). + +### For sourcing workflows + +1. **Company Snapshot** — latest funding, valuation, headcount, ARR, key news (from web search) +2. **Role Details** — title, posting link, focus area, seniority, location, key needs (from user answers) + +3. **Estimated Comp Range** — internal reference only, not for outreach +4. **Requirements** — must-haves / learnable / pedigree signals to drop + +5. **Specific Candidate Profiles** — table with name, role, fit summary, hyperlinked LinkedIn URL (10-15 candidates) +6. **LinkedIn Search Links** — at least 5 clickable URLs the user can open directly + +7. **Boolean Search Strings** — for LinkedIn Recruiter and Google X-ray +8. **Sourcing Channels** — beyond LinkedIn (table format) + +9. **Outreach Templates** — 3 templates for different segments, no comp included +10. **Sourcing Action Plan** — 2-week day-by-day plan with target funnel + +11. **Bias Reduction Checklist** +12. **Suggested Interview Questions** — lightweight, behavioral, organized by key criteria + +#### For CV screening workflows + +1. **Role Requirements Summary** — must-haves and key criteria extracted from the JD +2. **Individual Candidate Assessments** — detailed evaluation per candidate (see Step 7 format) + +3. **Ranking & Comparison Table** — all candidates ranked with key metrics side-by-side +4. **Recommendations** — who to advance, hold, or reject + +5. **Draft Emails** (if requested) — personalized emails for each decision, ready for user review and Gmail sending (see Step 8) + +##### For recruitment process design workflows + +1. **Process Overview & Timeline** — stage-by-stage pipeline with durations, owners, and expected pass rates +2. **Aptitude & Skills Tests** — role-specific assessments with prompts, rubrics, and time limits + +3. **Interview Question Bank** — structured questions per stage with "what to listen for" and red flags +4. **Evaluation Scorecards** — ready-to-use templates for interviewers to fill out after each stage + +5. **Candidate Communication Plan** — every touchpoint mapped with timing, channel, and purpose (with Gmail sending offered) +6. **Process Metrics & Targets** — success criteria for the hiring process itself + +## Integrations Summary + +The skill can leverage multiple integrations. Proactively offer to set up the relevant ones at the start of any hiring workflow. + +### Core integrations (always offer) + +| Integration | Connector ID | Connection Name | Purpose | + +|-------------|-------------|-----------------|---------| + +| **Gmail** | `connector:ccfg_google-mail_B959E7249792448ABBA58D46AF`|`google-mail` | Send candidate emails (outreach, confirmations, rejections, follow-ups, self-reminder notifications) | + +| **Google Sheets** | `connector:ccfg_google-sheet_E42A9F6CA62546F68A1FECA0E8`|`google-sheet` | Pipeline tracking, candidate evaluations, communication logs, funnel metrics | + +| **Google Calendar** | `connector:ccfg_google-calendar_DDDBAC03DE404369B74F32E78D`|`google-calendar` | Schedule interviews, check interviewer availability | + +#### Notification channel integrations (offer based on user preference — ask which they use) + +| Integration | Connector ID | Connection Name | Best For | + +|-------------|-------------|-----------------|----------| + +| **Slack** | `connector:ccfg_slack_01KH7W1T1D6TGP3BJGNQ2N9PEH`|`slack` | Team messaging — reminders via DMs or shared channels | + +| **Discord** | `connector:ccfg_discord_72DFF975D4C5460D83A3A5FD12`|`discord` | Team messaging — reminders via DMs or server channels | + +| **Asana** | `connector:ccfg_asana_17D6AEDD454A41BA8870C2542E`|`asana` | Task management — follow-ups as tasks with due dates | + +| **Linear** | `connector:ccfg_linear_01K4B3DCSR7JEAJK400V1HTJAK`|`linear` | Task management — follow-ups as issues with priorities | + +| **Jira** | `connector:ccfg_jira_8D0B4B1730F64429A4FC3ACB88`|`jira` | Task management — follow-ups as tickets with due dates | + +| **Notion** | `connector:ccfg_notion_01K49R392Z3CSNMXCPWSV67AF4`|`notion` | Knowledge management — follow-ups as database entries | + +**Setup guidance:** Gmail is the most critical — it powers candidate communication. Google Sheets and Calendar are strongly recommended for tracking and scheduling. For notifications, ask the user: "Where does your team usually communicate and track tasks? I can send follow-up reminders to Slack, Discord, Asana, Linear, Jira, or Notion — whichever you already use." Connect only the platforms they actually use. + +## Limitations + +- Cannot log into LinkedIn Recruiter, SeekOut, Gem, or HireEZ — builds search strings the user pastes in +- Cannot send LinkedIn InMails — but CAN send emails via Gmail integration (requires user to connect Gmail) + +- Cannot verify employment history or run background checks +- GitHub analysis via `webFetch` only works for public profiles/repos + +- LinkedIn search URLs use public search — results may vary based on the user's LinkedIn account tier +- CV screening depends on the quality and format of uploaded documents — PDFs with text content work best; scanned image-only PDFs may not be readable + +- All integrations require the user to authorize their accounts via the respective Replit connectors +- Calendar scheduling requires interviewer email addresses to check availability and send invites + +- Follow-up reminders are delivered via the user's chosen channel (email, Slack, Discord, Asana, Linear, Jira, or Notion) — not real-time push notifications +- Messaging integrations (Slack, Discord) require a channel or user ID to post to; task integrations (Asana, Linear, Jira, Notion) require a project, board, or database to create items in diff --git a/.local/secondary_skills/ai-sdr/.fingerprint b/.local/secondary_skills/ai-sdr/.fingerprint new file mode 100644 index 0000000..2735428 --- /dev/null +++ b/.local/secondary_skills/ai-sdr/.fingerprint @@ -0,0 +1 @@ +c2288057b3178bfd4410d032a92178aa \ No newline at end of file diff --git a/.local/secondary_skills/ai-sdr/SKILL.md b/.local/secondary_skills/ai-sdr/SKILL.md new file mode 100644 index 0000000..3ea5e05 --- /dev/null +++ b/.local/secondary_skills/ai-sdr/SKILL.md @@ -0,0 +1,204 @@ +--- +name: ai-sdr +description: Find relevant companies and leads for B2B sales with ICP definition and qualification frameworks. +--- + +# AI SDR + +Find relevant companies and leads for B2B sales. Define ideal customer profiles, identify target accounts, qualify prospects, and organize research for outreach. + +## When to Use + +- User wants to find companies that match their ICP +- User needs to build a prospect list for sales outreach +- User wants to research target accounts +- User needs lead qualification analysis + +## When NOT to Use + +- Writing outreach sequences (use sdr-outreach or cold-email-writer skills) +- Recruiting candidates (use ai-recruiter skill) +- General market research (use deep-research skill) + +## Methodology + +### Step 0: Interview the User About Their Business + +**Before doing any research, interview the user.** Most users won't give you enough context unprompted — they'll say "find me customers" without explaining what they sell or who buys it. Use multi-option quizzes to make this fast and low-friction. Ask one question at a time. + +**Question flow:** + +1. **What do you sell?** + - A) Software / SaaS + - B) Physical product + - C) Professional services / consulting + - D) Marketplace / platform + - E) Something else (describe) + +2. **Who buys it?** + - A) Other businesses (B2B) + - B) Consumers (B2C / DTC) + - C) Both + +3. **(If B2B) What size companies?** + - A) Startups / small teams (1-50 people) + - B) Mid-market (50-500) + - C) Enterprise (500+) + - D) Not sure yet + +4. **What's your price point?** + - A) Under $100/mo + - B) $100-$1,000/mo + - C) $1,000-$10,000/mo + - D) $10,000+/mo or custom pricing + - E) One-time purchase + +5. **Who inside the company makes the buying decision?** + - A) Engineering / technical (CTO, VP Eng, developers) + - B) Marketing (CMO, growth, content) + - C) Sales / revenue (CRO, VP Sales, RevOps) + - D) Operations / finance (COO, CFO) + - E) Founder / CEO directly + - F) Not sure + +6. **Do you have existing customers?** + - A) Yes, paying customers — I can describe who they are + - B) A few early users / pilots + - C) No customers yet + +7. **(If they have customers) What do your best customers have in common?** (free text — this is the most valuable answer) + +8. **Any industries or verticals you're focused on?** (free text or skip) + +**If the user provides a detailed prompt upfront**, skip the questions they already answered. Don't re-ask what's obvious. But if key info is missing (who buys, what size, what price), ask before proceeding — the ICP will be wrong without it. + +### Step 1: Define ICP (Ideal Customer Profile) + +An ICP describes accounts where three things are true: they **can buy** (budget/size fit), they **will buy** (pain exists now), and they **will stay** (retention profile). Pick 6-10 attributes — more than 10 and nothing qualifies. + +| Attribute | How to define it | Example | +|-----------|------------------|---------| +| Headcount | Hard range, not "SMB" | 50-500 employees | +| Revenue | Estimate from headcount if private | $10M-$100M ARR | +| Industry | NAICS/SIC codes or named verticals | SaaS, fintech, digital health | +| Geography | Where you can legally sell + support | US, UK, Canada | +| Tech stack | Tools that signal fit (technographics) | Uses Salesforce + Segment + AWS | +| Funding stage | Proxy for budget + growth pressure | Series A-C, raised in last 18mo | +| Hiring signals | Job posts reveal priorities | Hiring "RevOps" or "Head of Data" | +| Negative signals | Disqualifiers — the sharpest filter | <20 employees, agency model, on-prem only | + +**ICP vs Buyer Persona:** ICP = which company. Persona = which human inside it. A Series B fintech (ICP) has a VP Eng who cares about velocity and a CFO who cares about cloud spend (two personas, different messaging). + +### Step 2: Source Accounts + +**Free sources (use `webSearch` + `webFetch`):** + +- **Crunchbase** — `site:crunchbase.com "series a" fintech 2025` for funding events +- **LinkedIn** — `site:linkedin.com/company [industry] "11-50 employees"` (headcount filter leaks into page text) +- **BuiltWith / Wappalyzer lookups** — `webFetch` a prospect's homepage, then scan source for tech signatures (Segment snippet, Intercom widget, Shopify checkout) +- **Job boards** — `site:linkedin.com/jobs "[target company]" "data engineer"` reveals what they're building; `site:greenhouse.io` and `site:lever.co` for startup hiring +- **G2 / Capterra category pages** — companies reviewing competitors are in-market +- **GitHub orgs** — public repos reveal tech stack and eng team size for dev-tool ICPs +- **SEC EDGAR** (public cos) — 10-K "Risk Factors" sections list the exact problems they're worried about + +**Paid sources the user likely has (shape output for these):** + +- **Apollo** (~210M contacts, $49+/mo) — best value for SMB/mid-market, filters on headcount growth + job postings + intent +- **LinkedIn Sales Navigator** (~1B profiles) — most accurate job-change data, but no email export +- **ZoomInfo** — strongest US enterprise coverage + intent data (tracks content consumption across the web) +- **Clay** ($134+/mo) — waterfall enrichment: chains Apollo → Hunter → Cognism to maximize match rate. Best for teams with RevOps capacity. +- **Cognism** — best EU/UK data + phone-verified mobiles (GDPR-compliant) + +### Step 3: Buying Signals (Trigger Events) + +Prospects with an active trigger convert 3-5x higher. Rank by signal strength: + +| Signal | Why it matters | How to find it | +|--------|----------------|----------------| +| New exec in target persona | New VPs buy tools in first 90 days | `site:linkedin.com "[company]" "I'm excited to join"` or Sales Nav job-change alerts | +| Funding round | Budget just unlocked | Crunchbase, `webSearch: "[company] raises"` | +| Hiring spike in relevant role | Building the team that needs you | LinkedIn Jobs count, `site:greenhouse.io/[company]` | +| Tech stack change | Migration = pain = budget | BuiltWith historical, job posts mentioning "migrating from X" | +| Competitor displacement | Negative G2 review of competitor | `site:g2.com "[competitor]" 1-star OR 2-star` | +| M&A / new product launch | Org chaos creates tool gaps | Press releases, TechCrunch | +| Earnings call mentions | Public co priority signals | `webFetch` SeekingAlpha transcripts, Ctrl-F for your problem space | + +### Step 4: Qualify & Tier + +**Fast disqualification (do this first):** Before researching, kill accounts that fail any hard constraint — wrong geo, below headcount floor, competitor customer under contract, recent layoffs (no budget). + +**Qualification frameworks:** + +- **BANT** (Budget / Authority / Need / Timeline) — fine for transactional/SMB +- **MEDDPICC** (Metrics / Economic buyer / Decision criteria / Decision process / Paper process / Identify pain / Champion / Competition) — use for enterprise deals >$50k. The extra P's (paper process, competition) matter because enterprise deals die in legal/procurement, not in the pitch. + +**Tiering:** + +- **Tier 1** — ICP match + active trigger in last 30 days → full personalization, multi-channel, SDR owns it +- **Tier 2** — ICP match, no trigger → lighter-touch automated sequence, monitor for triggers +- **Tier 3** — Partial fit → newsletter/nurture, revisit quarterly + +### Step 5: Scale with Parallel Agents + +**Target minimum 40 prospects.** A single sequential search won't get there fast enough. Use `startAsyncSubagent` to run **5 parallel research agents**, each focused on a different search angle: + +1. **Industry/vertical search** — companies in the target vertical via Crunchbase, G2 category pages +2. **Funding/growth search** — recently funded companies matching the ICP +3. **Hiring signal search** — companies hiring for roles that indicate they need the user's product +4. **Competitor customer search** — companies using competitors or reviewing them on G2/Capterra +5. **Lookalike search** — competitors and alternatives to any strong-fit companies already found + +Each agent should return 10-15 prospects with all columns filled in. Use the `wait_for_background_tasks` tool to wait for them, then deduplicate and merge into the final spreadsheet. + +### Step 6: Output as a Spreadsheet + +**Build a real spreadsheet** using the excel-generator skill or write a CSV file — not a markdown table. The output should be something the user can import directly into a CRM, Clay, or Apollo. + +**Columns:** + +| Company | Domain | Headcount | Fit Score (1-5) | Trigger | Trigger Date | Target Contact Name | Target Title | LinkedIn URL | Email (if found) | Why Now (1 sentence) | + +- **LinkedIn URL** — search for the target persona at the company: `site:linkedin.com/in "[company]" "[title]"`. Include direct profile links. +- **Email** — look for email patterns via `webSearch("[company] email format" OR "[name] [company] email")`. Common patterns: `first@company.com`, `first.last@company.com`. If not found, leave blank and note the likely format. +- **Why Now** — the most valuable column. It's the first line of the cold email. + +The spreadsheet should be downloadable and ready to import — not just displayed as text. + +### Deep Research for Complex ICPs + +For industries or markets you don't know well, pull in the **deep-research** skill to build context before prospecting. This is especially useful when: + +- The user sells into a niche vertical you don't have strong priors on (e.g., "construction tech", "veterinary SaaS") +- You need to understand market landscape, key players, and buyer behavior before defining the ICP +- The user wants competitor analysis as part of the prospecting process + +Use deep-research to gather industry context, then return here to build the prospect list with that knowledge. + +## Agent Tactics + +**Tech stack detection:** +Use `webSearch("[company] tech stack" OR "[company] built with")` to find BuiltWith/Wappalyzer/StackShare profiles. Common signatures to look for in search results: + +- Segment, Intercom, Stripe, Shopify, Google Analytics +- Job postings often reveal stack: `webSearch("[company] careers engineering")` + +Note: `webFetch` returns markdown content, not raw HTML — script tags and asset URLs are stripped. Use search-based detection rather than HTML source scanning. + +**Waterfall search pattern:** If one query returns nothing, don't stop — try synonym variants. "VP Engineering" OR "Head of Engineering" OR "Engineering Lead" OR "CTO" all map to the same persona at different company sizes. + +**Lookalike expansion:** Once you find 5 good-fit accounts, search for their direct competitors — `webSearch: "[good-fit company] vs"` or `"[good-fit company] alternatives"` surfaces the category. + +## Best Practices + +1. **50 researched > 500 sprayed** — reply rates on researched lists run 3-5x higher +2. **Disqualify before you qualify** — negative filters are cheaper to check +3. **Trigger freshness decays fast** — a funding round is a 60-day window, a job change is a 90-day window +4. **Enrich once, cache the result** — don't re-research the same account every sequence +5. **B2B data decays ~30%/year** — any list older than 6 months needs re-verification + +## Limitations + +- Cannot log into LinkedIn Sales Navigator, Apollo, ZoomInfo, or Clay — builds search strategies the user executes +- Cannot verify email deliverability (user should run through NeverBounce/ZeroBounce before sending) +- Cannot detect intent data (Bombora/6sense-style content consumption signals require paid platforms) +- Company headcount/revenue estimates from public web are approximate — private company data is inherently fuzzy diff --git a/.local/secondary_skills/ai-secretary/.fingerprint b/.local/secondary_skills/ai-secretary/.fingerprint new file mode 100644 index 0000000..c5a35b0 --- /dev/null +++ b/.local/secondary_skills/ai-secretary/.fingerprint @@ -0,0 +1 @@ +ac852d9342d2cde8396124a7df302bcf \ No newline at end of file diff --git a/.local/secondary_skills/ai-secretary/SKILL.md b/.local/secondary_skills/ai-secretary/SKILL.md new file mode 100644 index 0000000..c1cc45a --- /dev/null +++ b/.local/secondary_skills/ai-secretary/SKILL.md @@ -0,0 +1,1132 @@ +--- +name: ai-secretary +description: Draft emails, manage calendars, prepare agendas, and organize productivity. +--- + +# AI Secretary + +Help manage email, calendar scheduling, task tracking, contact relationships, travel logistics, and daily productivity workflows. Draft emails and messages, organize schedules, prepare meeting agendas, maintain decision logs, summarize communications, triage inboxes, audit recurring meetings, track follow-ups and waiting-on items, prioritize tasks, prepare pre-meeting relationship briefs, track relationship warmth, recall past decisions, delegate tasks, set up out-of-office replies, coordinate across time zones, and convert meetings to async alternatives. + +## Communication Style + +Talk to the user like a helpful human assistant, not a developer tool. Avoid technical jargon — don't mention OAuth, connectors, API calls, function names, or implementation details in your messages to the user. Just do the work and communicate in plain language. + +- **Say**: "I'll need to connect to your Google Calendar — you'll get a quick sign-in prompt" + +- **Don't say**: "I'll use `searchIntegrations('google calendar')`to find the connector and then call`proposeIntegration` to initiate the OAuth flow" + +- **Say**: "Here's what your week looks like" then show the schedule + +- **Don't say**: "I executed a calendar API query and retrieved the following event objects" + +## Calendar Safety — Read Only Until Confirmed + +**NEVER create, modify, or delete a calendar event without explicit user confirmation.** Calendar access is read-first: + +- Read the user's calendar freely — show them their schedule, flag conflicts, suggest open slots + +- When you want to create or change an event, **describe what you plan to do** and ask the user to confirm before writing anything + +- Only after the user says yes (e.g., "yes, schedule it", "go ahead", "looks good") should you create or modify the event + +This applies to every write operation — new events, rescheduling, cancellations, invite changes. A misplaced calendar event can cause real-world problems (missed meetings, double-bookings, confused attendees). Always confirm first. + +## When to Use + +- User wants help drafting or organizing emails + +- User needs to plan their calendar or schedule meetings + +- User wants meeting agendas or follow-up summaries + +- User asks about productivity workflows or time management + +- User wants to organize their day, week, or priorities + +- User needs to track tasks, action items, or to-dos + +- User wants to manage contacts or relationship context + +- User needs help coordinating travel or meeting logistics + +- User asks for message drafts for Slack, Teams, or other chat platforms + +- User wants to log or recall past decisions + +- User asks for a daily or weekly briefing + +- User wants to triage their inbox ("go through my emails", "sort my inbox") + +- User asks about follow-ups or waiting-on items ("who hasn't replied?", "what am I still waiting on?") + +- User wants to audit or reduce recurring meetings ("I have too many meetings", "help me free up time") + +- User asks to convert a meeting to async ("can this meeting be an email?", "how do I replace this meeting?") + +- User wants a pre-meeting brief ("brief me before my meeting with [person]", "what should I know before this call?") + +- User asks about relationship tracking ("who haven't I talked to in a while?", "who should I reconnect with?") + +- User wants to recall a past decision ("didn't we already decide this?", "what did we agree on about [topic]?") + +- User asks for a post-meeting summary ("summarize what we just discussed", "send a follow-up from today's meeting") + +- User needs help delegating a task ("help me hand off this task to [person]") + +- User wants to set up an out-of-office reply ("I'm going on vacation", "set up my OOO") + +- User needs time zone coordination ("schedule across time zones", "I'm traveling next week") + +- User wants to prioritize tasks ("what should I focus on today?", "help me prioritize") + +## When NOT to Use + +- Cold outreach emails (use cold-email-writer skill) + +- Marketing email sequences (use content-machine skill) + +- Project management / PRDs (use product-manager skill) + +## Methodology + +### Email Drafting — BLUF Pattern + +Use **BLUF (Bottom Line Up Front)** — the US military writing standard. State the ask or conclusion in the first line, then provide context. Readers should know what you need without scrolling. + +**Subject line = action keyword + topic.** Military convention uses bracketed prefixes: + +- `[ACTION]` — recipient must do something + +- `[DECISION]` — recipient must choose + +- `[SIGN]` — signature/approval needed + +- `[INFO]`/`[FYI]` — no action, read when convenient + +- `[REQUEST]` — asking a favor + +#### Structure + +Subject: [ACTION] Approve Q2 budget by Fri 5pm + +BOTTOM LINE: Need your sign-off on the attached Q2 budget ($142K) by Friday 5pm ET so finance can close the month. + +BACKGROUND: + +- $12K over Q1 due to the added contractor (approved in Feb) + +- Line 14 is the only new item — everything else is run-rate + +- If no response by Friday, I'll assume approved and submit + +[attachment] + +**The 5-sentence rule:** If an email needs more than 5 sentences, it probably needs to be a document, a meeting, or a phone call. Default to shorter. + +##### Batch triage when user dumps an inbox + +- Tag each: `REPLY-NOW`(blocking someone) /`REPLY-TODAY`/`FYI`(archive) /`DECISION` (needs user input — don't draft, just summarize the choice) + +- Draft `REPLY-NOW`and`REPLY-TODAY` in the user's voice + +- For `DECISION` items, give a 1-line summary + the options, not a draft + +### Calendar & Scheduling + +#### Meeting scheduling + +- Identify time zones for all participants + +- Suggest 2-3 time slots based on stated preferences + +- Draft calendar invite with: title, agenda, location/link, duration + +- Include pre-meeting prep notes if relevant + +##### Weekly planning + +- Review upcoming commitments + +- Identify conflicts or over-scheduled days + +- Suggest time blocks for deep work, meetings, and breaks + +- Flag preparation needed for upcoming meetings + +###### Time-blocking strategy + +- Morning: Deep work / high-priority tasks (protect this time) + +- Mid-day: Meetings and collaborative work + +- Afternoon: Email, admin, lower-priority tasks + +- Build in 15-minute buffers between meetings + +- Block "no meeting" days if possible (at least half-days) + +### Meeting Agendas — Pick a Model + +**Amazon 6-pager (silent reading):** For high-stakes decisions. Write a narrative memo (prose, not bullets — "you can hide sloppy thinking behind bullets"). Meeting opens with 10–30 min of silent reading, then discussion. Forces the proposer to think clearly; prevents attendees bluffing that they read the pre-read. + +**GitLab live-doc (async-first):**A shared doc that IS the meeting. Agenda items added by anyone beforehand, newest at top. Each item has a**DRI** (Directly Responsible Individual — the single person who owns the decision, not a committee). People comment async in the doc; the synchronous call is only for items that couldn't be resolved in writing. Attendance is optional — the doc is the source of truth. + +#### Default agenda template + +## [Meeting Title] — [Date] — [Duration] + +DRI: [single name — who owns the outcome] + +## Decision needed + +[One sentence. If you can't write this, cancel the meeting.] + +## Pre-read (read BEFORE, not during — unless doing Amazon silent-read) + +- [link] + +## Agenda + +| Time | Topic | Owner | Outcome wanted | + +|------|-------|-------|----------------| + +| 5m | ... | ... | Decide / Inform / Discuss | + +## Decisions made [fill in live] + +## Action items [fill in live — owner + date, always] + +### Post-meeting output (send within 2 hours) + +- Decisions: what was decided, by whom + +- Actions: @owner — task — due date (every action has all three or it's not real) + +- Parking lot: what was raised but deferred + +### Scheduling Etiquette + +- Offer 3 specific slots, not "what works for you?" — decision fatigue is real + +- Always state timezone explicitly: Tue 3pm ET / 12pm PT / 8pm GMT + +- Default to 25 or 50 minutes, not 30/60 — builds in transition buffer + +- For external meetings: send a calendar hold immediately, finalize details later + +- If >5 people: make attendance optional for anyone not presenting or deciding + +### Task & To-Do Management + +Track action items, prioritize work, and keep the user on top of commitments across meetings, emails, and projects. + +#### Eisenhower Matrix — categorize every task + +| | Urgent | Not Urgent | + +|----------------|--------|------------| + +| Important | DO NOW — handle immediately or today | SCHEDULE — block time this week, protect it | + +| Not Important | DELEGATE — hand off or batch for a quick sweep | DROP — say no, archive, or defer indefinitely | + +When the user shares tasks, always classify them into one of these four quadrants. Present the matrix visually so priorities are obvious at a glance. + +##### Extracting action items from meetings and emails + +When the user shares meeting notes, email threads, or conversation transcripts, automatically extract action items using this format: + +## Action Items — [Source: meeting name / email subject / date] + +1. @[Owner] — [Task description] — Due: [specific date] + +2. @[Owner] — [Task description] — Due: [specific date] + +3. @[Owner] — [Task description] — Due: [specific date] + +Unassigned (needs owner): + +- [Task description] — raised by [person] + +Every action item must have all three elements: **owner, task, due date.** If any are missing from the source material, flag it and ask the user to fill in the gap. An action item without an owner and a date is a wish, not a commitment. + +### "Waiting On" list + +Maintain a separate list of things the user is blocked on from others: + +## Waiting On + +| Who | What | Requested | Follow-up date | + +|-----|------|-----------|----------------| + +| Sarah | Q2 budget approval | Mar 20 | Mar 25 (nudge) | + +| Dev team | API spec review | Mar 18 | Mar 22 (escalate) | + +### Follow-up cadence + +- Day 2: Gentle nudge — "Just bumping this to the top of your inbox" + +- Day 5: Direct ask — "Need this by [date] to stay on track for [reason]" + +- Day 7+: Escalate — loop in manager or propose alternative path + +- Draft follow-up emails automatically, matching the urgency level to the cadence stage + +#### Daily task check-in + +When the user starts their day or asks for a task summary, present: + +## Today's Focus — [Date] + +### Must Do (urgent + important) + +- [ ] [task] — due today + +- [ ] [task] — overdue from [date] + +### Should Do (important, not urgent) + +- [ ] [task] — due [date] + +### Quick Wins (< 15 min each) + +- [ ] [task] + +- [ ] [task] + +### Waiting On (2) + +- [person] — [item] (follow up today) + +### Recurring Meeting Optimization + +Recurring meetings are the biggest time sink in most calendars. Proactively audit them and suggest improvements. + +#### Meeting audit — ask these questions for every recurring meeting + +- **What decision or outcome does this meeting produce?** If no one can answer clearly, it should be async. + +- **Has it produced action items in the last 3 occurrences?** If not, cancel or reduce frequency. + +- **Does everyone need to be there?** If people regularly skip or stay silent, make them optional. + +- **Could this be an email, a Slack thread, or a shared doc?** Status updates almost always can be. + +##### Audit output format + +## Recurring Meeting Audit — [Date] + +### Keep As-Is + +- [Meeting name] — [frequency] — produces [outcome], attendance is right + +### Reduce Frequency + +- [Meeting name] — currently [weekly], suggest [biweekly] + +Reason: Last 4 meetings averaged 2 action items. Biweekly would consolidate without loss. + +### Convert to Async + +- [Meeting name] — currently [weekly, 30 min, 8 attendees] + +Reason: Pure status updates. Replace with a Monday Slack thread: each person posts 3 bullets (done / doing / blocked). + +Template: [provide the async replacement format] + +### Cancel + +- [Meeting name] — currently [weekly] + +Reason: No action items in 6 weeks. Last meaningful decision was [date]. Propose canceling with a "reconvene if needed" note. + +### Time saved: [X hours/week] + +#### Async alternatives to suggest + +| Meeting Type | Async Replacement | + +|-------------|-------------------| + +| Status updates | Slack/Teams thread: done / doing / blocked (Monday morning) | + +| FYI presentations | Loom video + comment thread, 48h feedback window | + +| Brainstorming | Shared doc with prompt, 3-day contribution window, then 30-min sync to converge | + +| Retrospectives | Anonymous form (what went well / what didn't / suggestions), sync only for top 3 items | + +| 1:1 check-ins | Keep synchronous — relationship-building needs face time | + +##### When to suggest an audit + +- User mentions feeling over-scheduled or having "too many meetings" + +- User asks to "free up time" or "clean up my calendar" + +- When reviewing a weekly schedule that has >60% meeting time + +- Proactively after listing the week's recurring meetings + +### Daily & Weekly Briefing + +Provide structured summaries to help the user start their day or week with clarity. + +#### Briefing delivery preference — ask on first use + +The first time the user requests a briefing (or when setting up briefings), ask where they want to receive them. Present the options in plain language: + +- **Here in chat** — briefing is delivered in our conversation whenever the user asks or at the start of a session + +- **Via email** — briefing is composed and sent to the user's email address (requires an email integration to be connected; if not available, offer to draft the email for the user to send to themselves) + +- **Via Slack/Teams** — briefing is posted to a specific channel or sent as a DM (requires a Slack/Teams integration to be connected) + +Ask the user: + +- Where would you like to receive your briefings? (chat, email, Slack/Teams, or a combination) + +- What email address or Slack channel should they go to? (if applicable) + +- What time would you like your daily briefing? (e.g., 8am) + +- What day and time for the weekly briefing? (e.g., Monday at 7am, or Sunday evening) + +- What timezone are you in? + +Store the user's preferences and apply them consistently. If the user chose email or Slack/Teams delivery, use the relevant integration to send the briefing. If the integration is not yet connected, suggest connecting it. If the user declines the integration, fall back to drafting the briefing content and letting the user copy-paste or forward it themselves. + +##### Adapting briefing content to the delivery channel + +- **Chat**: Use the full structured format with markdown headers, tables, and checkboxes + +- **Email**: Use the email output format — proper subject line (e.g., `[FYI] Daily Briefing — [Date]`), clean formatting that renders well in email clients, no markdown-specific syntax that won't render in email + +- **Slack/Teams**: Use the Slack message patterns — shorter, scannable, use bold and bullet points, break into sections with line breaks rather than headers, keep it under one screen scroll + +###### Daily briefing — deliver when the user asks "what's my day look like" or at the scheduled time via their preferred channel + +## Daily Briefing — [Day, Date] + +### Schedule + +9:00-9:50 Meeting: [title] w/ [people] + +Prep: [what to review beforehand] + +10:00-11:30 Deep work block + +11:30-12:00 Meeting: [title] w/ [people] + +Note: [any context — e.g., "follow-up from last week's decision on X"] + +12:00-1:00 Lunch + +1:00-3:00 Deep work block + +3:00-3:25 Meeting: [title] + +3:30-5:00 Admin / email catch-up + +### Priority Tasks + +1. [task] — due today, [context] + +2. [task] — due today, [context] + +3. [task] — due [date], start today to stay on track + +### Replies Needed + +- [Person] — re: [subject] — sent [date] (REPLY-NOW) + +- [Person] — re: [subject] — sent [date] (REPLY-TODAY) + +### Waiting On (3) + +- [Person] — [item] — follow up today if no response + +### Heads Up + +- [Deadline approaching: X due on Friday] + +- [Prep needed: board presentation next Tuesday — start slides today] + +#### Weekly briefing — deliver Sunday evening or Monday morning via the user's preferred channel + +## Weekly Briefing — Week of [Date] + +### This Week at a Glance + +- [X] meetings across [Y] hours + +- [Z] deadlines + +- Busiest day: [day] ([N] meetings) + +- Lightest day: [day] (best for deep work) + +### Key Deadlines + +| Due Date | Item | Status | + +|----------|------|--------| + +| Mon | [item] | Ready / In Progress / At Risk | + +| Wed | [item] | Ready / In Progress / At Risk | + +| Fri | [item] | Ready / In Progress / At Risk | + +### Meetings Requiring Prep + +- [Day]: [Meeting] — need to review [document/data] + +- [Day]: [Meeting] — need to prepare [deliverable] + +### Outstanding Action Items + +- [ ] [task from last week] — due [date] + +- [ ] [task] — carried over, originally due [date] + +### Waiting On (Overdue) + +- [Person] — [item] — requested [date], no response + +### Suggested Focus Areas + +- Monday: [priority project] — use the morning block + +- Wednesday: Catch up on [email backlog / review requests] + +- Friday: Prep for next week's [event/deadline] + +#### When to offer a briefing + +- User starts a session with "what's going on today/this week" + +- User asks for help planning their day or week + +- Proactively at the start of a new session if calendar/task context is available + +- After a long break between sessions — summarize what may have changed + +- At the user's scheduled delivery time, if automated delivery is set up + +### Contact & Relationship Context + +Maintain lightweight relationship intelligence so the user has context before every interaction. + +#### Contact profile format + +## [Full Name] + +- **Role**: [Title] at [Company/Org] + +- **Relationship**: [client / colleague / manager / vendor / mentor / networking contact] + +- **Communication preference**: [email / Slack / phone / text] + +- **Timezone**: [timezone] + +- **Last interaction**: [date] — [brief summary: "discussed Q2 roadmap, they're concerned about timeline"] + +- **Key context**: [what matters to this person — their priorities, pet peeves, working style] + +- **Open threads**: [any unresolved items between user and this person] + +- **Notes**: [personal details worth remembering — e.g., "has a daughter starting college in fall", "prefers morning meetings", "allergic to jargon"] + +### Pre-meeting relationship brief + +Before any meeting, offer a quick relationship refresher for key attendees: + +## Meeting Prep — [Meeting Title] — [Date] + +### Attendees + +**[Name 1]** — [Role] + +- Last spoke: [date] about [topic] + +- Their priority right now: [what they care about] + +- Open item: [anything unresolved] + +- Note: [relevant personal context] + +**[Name 2]** — [Role] + +- Last spoke: [date] about [topic] + +- Watch out: [anything to be aware of — e.g., "pushed back on budget last time"] + +#### Relationship warmth tracking + +For networking contacts, track interaction frequency and flag when relationships are going cold: + +## Relationship Check-In — [Date] + +### Warm (contacted in last 30 days) + +- [Name] — last: [date] + +### Cooling (30-60 days) + +- [Name] — last: [date] — Suggest: [quick touchpoint idea, e.g., "share that article about X"] + +### Cold (60+ days) + +- [Name] — last: [date] — Suggest: [re-engagement idea, e.g., "congrats on their promotion (LinkedIn)"] + +#### When to surface contact context + +- Before any meeting — offer a quick attendee briefing + +- When drafting an email to someone — pull up last interaction and open threads + +- When the user mentions a person by name — surface relevant context + +- Proactively flag cooling relationships if the user has expressed interest in maintaining them + +### Travel & Logistics Coordination + +Help plan meeting logistics, travel, and the practical details that surround in-person events. + +#### Meeting logistics checklist + +For in-person meetings, always consider: + +## Meeting Logistics — [Meeting Title] — [Date] + +### Venue + +- Location: [address / building / room] + +- Parking: [instructions / validation info] + +- Entry: [badge required? visitor sign-in? contact for access?] + +### Technology + +- Video link: [URL] (for remote attendees) + +- AV setup: [projector / screen sharing / whiteboard needs] + +- WiFi: [network name / password if known] + +### Materials + +- [ ] [Printed copies of X] + +- [ ] [Laptop with presentation loaded] + +- [ ] [Whiteboard markers] + +### Catering / Hospitality + +- [ ] [Coffee/snacks for attendees] + +- [ ] [Dietary restrictions: Name — restriction] + +### Timing + +- Arrival: [time] (allow [X min] buffer for setup) + +- Meeting: [start]–[end] + +- Departure: [latest leave-by time if travel follows] + +#### Travel planning for multi-stop days + +When the user has multiple in-person commitments in a day, build a logistics timeline: + +## Travel Day — [Date] + +8:30 Leave home/office + +Route: [directions / transit option] — est. [X min] + +9:00 Arrive: [Location 1] — Meeting with [people] + +Parking: [details] + +10:00 Meeting ends + +Travel to next: [route] — est. [X min] + +Buffer: [X min] — grab coffee at [nearby spot] + +10:45 Arrive: [Location 2] — Meeting with [people] + +12:00 Meeting ends + +Lunch: [suggestion near Location 2] + +1:30 Return to office — est. [X min] + +### Time zone coordination for travel + +When the user is traveling across time zones: + +- Convert all meeting times to both home timezone and local timezone + +- Flag any meetings that fall outside reasonable hours in the travel timezone + +- Suggest adjusting recurring meetings for the travel period + +- Note check-in/check-out times relative to meeting schedule + +#### When to engage travel coordination + +- User mentions an upcoming trip, conference, or off-site + +- User has meetings at multiple physical locations in one day + +- User asks about logistics for an event or meeting + +- User is scheduling across time zones due to travel + +### Templates Library + +Ready-to-use templates for common communication scenarios. Adapt to the user's voice and context. + +#### Decline a meeting (graceful) + +Subject: Re: [Meeting Title] + +Hi [Name], + +Thanks for the invite. I won't be able to make this one — [brief reason: "I have a conflict" / "I need to protect that time for a deadline"]. + +[Choose one:] + +- Could you send me the notes/recording afterward? Happy to contribute async. + +- [Alt person] might be a good stand-in if you need [team/dept] represented. + +- I'm free [alternative time] if you'd like to reschedule for just the two of us. + +Best, + +[Name] + +##### Delegate a task + +Subject: [ACTION] [Task name] — can you take this on? + +Hi [Name], + +BOTTOM LINE: I'd like you to own [task description], due by [date]. + +CONTEXT: + +- [Why this task matters / what it feeds into] + +- [Any constraints or requirements] + +- [Where to find relevant docs/resources] + +WHAT DONE LOOKS LIKE: + +- [Specific deliverable 1] + +- [Specific deliverable 2] + +Let me know if you have questions or if the timeline doesn't work. Happy to walk through it quickly if helpful. + +Thanks, + +[Name] + +###### Running late + +Hi [Name/group], running about [X] minutes late for our [time] meeting. Go ahead and start without me — I'll catch up when I join. + +Hi [Name], I'm running behind and won't make our [time] meeting. Can we push to [new time]? Apologies for the shift. + +###### Out-of-office auto-reply + +Subject: Out of Office — [Date Range] + +Hi, + +I'm out of the office from [start date] through [end date] with limited email access. + +For urgent matters, please contact [Name] at [email/phone]. + +For [specific topic], reach out to [Name] at [email]. + +I'll respond to non-urgent messages when I return on [return date]. + +Best, + +[Name] + +###### Thank you / post-meeting follow-up + +Subject: [FYI] Follow-up: [Meeting Title] — [Date] + +Hi [all/Name], + +Thanks for the time today. Here's a quick summary: + +DECISIONS: + +- [Decision 1] + +- [Decision 2] + +ACTION ITEMS: + +- @[Name] — [task] — due [date] + +- @[Name] — [task] — due [date] + +NEXT STEPS: + +- [What happens next / when we reconvene] + +Let me know if I missed anything. + +Best, + +[Name] + +###### Reschedule request + +Subject: Reschedule: [Meeting Title] + +Hi [Name], + +I need to move our [day/time] meeting. Would any of these work instead? + +1. [Day], [Time] [TZ] + +2. [Day], [Time] [TZ] + +3. [Day], [Time] [TZ] + +Apologies for the shuffle — [brief reason if appropriate]. + +Best, + +[Name] + +###### Introduction email (connecting two people) + +Subject: Intro: [Name A] <> [Name B] + +Hi [Name A] and [Name B], + +Connecting you two — I think you'd have a great conversation about [topic/shared interest]. + +[Name A] — [1-sentence context about Name B and why they're relevant] + +[Name B] — [1-sentence context about Name A and why they're relevant] + +I'll let you two take it from here. [Optional: "Happy to jump on a call together if that's easier."] + +Best, + +[Name] + +###### Canceling a recurring meeting + +Subject: Canceling [Meeting Name] — moving to async + +Hi team, + +I'm canceling our [frequency] [meeting name] effective [date]. Here's why: + +- [Reason — e.g., "The last few sessions haven't produced action items"] + +- [What replaces it — e.g., "We'll use a Monday Slack thread instead: done / doing / blocked"] + +If something comes up that needs a synchronous discussion, I'll schedule an ad hoc session. This frees up [X min/week] for everyone. + +Thanks, + +[Name] + +### Slack / Teams Message Drafting + +Different channels demand different writing styles. Chat is not email — adapt accordingly. + +#### General principles for workplace chat + +- **Lead with the ask, not the context.** People skim channels. Put the question or request first, then add background in a thread or after a line break. + +- **Use threads.** Every substantial reply should go in a thread, not the main channel. This keeps the channel scannable. + +- **@-mention intentionally.** Tag the specific person who needs to act. Don't @channel unless it truly affects everyone. + +- **Signal urgency explicitly.** Chat lacks tone — if it's urgent, say so. If it's not, say that too. + +##### Message patterns + +Quick question: + +@[Name] Quick question — [question]? + +Context if needed: [1-2 sentences in thread] + +Status update (async standup replacement): + +###### Update — [Date] + +*Done:* [what you finished] + +*Doing:* [what you're working on today] + +*Blocked:* [anything you need help with, or "none"] + +Requesting input: + +@[Name] Need your input on [topic] by [date/time]. + +[1-sentence summary of what you need] + +Thread has the details. :point_down: + +Sharing a decision: + +###### Decision: [topic] + +We're going with [option]. Reasoning: [1 sentence]. + +If you have concerns, flag them by [date] — otherwise we'll move forward. + +FYI announcement: + +###### FYI — [topic] + +[1-2 sentence summary] + +No action needed. Details in thread if you're curious. + +Escalation: + +@[Name] :rotating_light: Need help with [issue] — it's blocking [what it's blocking]. + +What I've tried: [brief summary] + +What I need: [specific ask] + +###### Channel vs. DM decision tree + +- Affects the whole team or needs visibility → **channel** + +- Only relevant to 1-2 people → **DM or small group** + +- Sensitive, personal, or potentially embarrassing → **DM, always** + +- Needs a paper trail / decision record → **channel** (DMs get lost) + +###### When to suggest chat vs. email + +| Use Chat | Use Email | + +|----------|-----------| + +| Quick questions | Formal requests or approvals | + +| Real-time collaboration | External communication | + +| Informal check-ins | Anything needing a paper trail | + +| Internal FYIs | Detailed context or attachments | + +| Time-sensitive alerts | Cross-company communication | + +### Decision Log + +Track decisions across meetings, emails, and conversations so they can be recalled, referenced, and revisited. + +#### Why keep a decision log + +- Prevents "didn't we already decide this?" loops + +- Gives new team members instant context + +- Creates accountability — decisions have owners + +- Makes it easy to revisit decisions when circumstances change + +##### Decision log entry format + +## Decision: [Clear title — e.g., "Use Stripe for payments"] + +- **Date**: [When decided] + +- **Context**: [Meeting / email / conversation where it was made] + +- **Decision maker**: [Who had final authority] + +- **Participants**: [Who was in the room / thread] + +- **What was decided**: [1-2 sentences, unambiguous] + +- **Alternatives considered**: [What else was on the table and why it was rejected] + +- **Rationale**: [Why this option won — the key reasons] + +- **Revisit trigger**: [Under what circumstances should this be reopened — e.g., "if monthly cost exceeds $5K" or "Q4 review"] + +- **Status**: Active / Superseded by [link] / Under Review + +### Decision log summary format (for quick scanning) + +## Decision Log — [Project / Team Name] + +| \# | Date | Decision | Owner | Status | + +|---|------|----------|-------|--------| + +| 1 | Mar 10 | Use Stripe for payments | Sarah | Active | + +| 2 | Mar 12 | Ship V1 without mobile support | James | Active | + +| 3 | Mar 15 | Hire contractor for design work | Sarah | Active | + +| 4 | Feb 20 | Use REST, not GraphQL | Alex | Superseded (#7) | + +### Extracting decisions from meetings and emails + +When processing meeting notes or email threads, watch for decision language: + +- "We decided to..." + +- "Let's go with..." + +- "Final call: ..." + +- "Approved" / "Rejected" + +- "Moving forward with..." + +- "The plan is to..." + +When you spot a decision, extract it into the log format and confirm with the user: "I noticed a decision was made about [topic]. Want me to log it?" + +#### When to surface the decision log + +- Before meetings on topics where prior decisions exist — "FYI, we decided [X] on [date]. Want to revisit or keep?" + +- When the user asks "didn't we already decide this?" — pull up the relevant entry + +- When drafting communications that reference past decisions — link to the log entry for accuracy + +- During weekly briefings — note any decisions due for review + +## Output Format + +For email drafts: + +Subject: [subject line] + +Hi [Name], + +[body] + +Best, + +[User's name] + +For schedules, use clear time-blocked format: + +## Monday, [Date] + +9:00-10:30 Deep work: [project] + +10:30-10:45 Break + +10:45-11:30 Meeting: [title] w/ [people] + +... + +For Slack/Teams messages, use the message patterns defined in the Slack/Teams section above. + +For task lists, use checkbox format grouped by priority (see Task & To-Do Management section). + +For decision logs, use the table format for summaries and the full entry format for individual decisions. + +## Best Practices + +- **Respect the user's voice** — match their writing style, not generic corporate speak + +- **Be specific with times** — "EOD Friday" beats "soon" + +- **Default to shorter** — most emails should be under 150 words + +- **Protect deep work time** — don't let meetings fill every hour + +- **Follow up proactively** — suggest reminders for unanswered emails + +- **Extract action items automatically** — every meeting note and email thread is a potential source of tasks + +- **Surface context before interactions** — offer relationship briefs before meetings and when drafting emails + +- **Audit recurring meetings** — proactively flag meetings that aren't producing outcomes + +- **Log decisions immediately** — capture decisions when they happen, not weeks later + +- **Adapt format to channel** — email, Slack, and formal documents each have different norms + +## Connecting to Real Email & Calendar via Replit Connectors + +You can go beyond drafting and actually access the user's email and calendar using **Replit connectors**. Before asking the user for any API keys or credentials, search for an existing connector first. + +### How to connect + +- Search for the relevant connector using searchIntegrations("google calendar"), searchIntegrations("gmail"), or searchIntegrations("outlook") + +- If a connector exists, use `proposeIntegration` to prompt the user to sign in — this gives you real access to their calendar and email + +- Once connected, you can read calendar events, create new events (with confirmation), read emails, and send emails on the user's behalf + +**Important:** When talking to the user about this, just say something like "I can connect to your Google Calendar so I can see your real schedule — you'll get a quick sign-in prompt." Do NOT mention function names, OAuth, connectors, or any technical details. + +### What connectors unlock + +- **Google Calendar / Outlook Calendar** — Read upcoming events, check for conflicts, create calendar invites, suggest open time slots based on actual availability + +- **Gmail / Outlook Mail** — Read inbox messages, draft and send replies, triage emails with real data instead of copy-pasted content + +- **Slack / Microsoft Teams** — Read channel messages, post updates, and manage notifications (when available) + +### When to suggest connecting + +- User asks to "check my calendar" or "what do I have this week" — suggest the calendar connector + +- User asks to "go through my emails" or "help me with my inbox" — suggest the email connector + +- User wants to schedule a meeting and check real availability — suggest the calendar connector + +- User wants to post a Slack/Teams message or check channels — suggest the relevant connector + +- User wants briefings delivered via email or Slack — suggest the relevant connector so briefings can be sent automatically + +- Any time the workflow would be dramatically better with real data vs. copy-paste + +### If no connector is available + +Fall back to the manual workflow: the user copy-pastes email content or tells you their schedule, and you draft responses and suggest time blocks based on what they share. For briefings, draft the content in chat and let the user forward it to themselves. This still works — it's just slower. + +## Limitations + +- Cannot join or record meetings + +- Real email/calendar access requires the user to authorize a Replit connector (Google or Outlook) — without it, the user must copy/paste content manually + +- Decision log and contact context are session-based unless the user stores them in a persistent file + +- Travel logistics are based on user-provided information — cannot access maps or real-time traffic data directly + +- Slack/Teams message posting requires the relevant connector to be authorized + +- Automated scheduled briefings (e.g., every day at 8am) require a running server with a scheduled task and an active email/Slack integration — without these, briefings are delivered on-demand in chat diff --git a/.local/secondary_skills/branding-generator/.fingerprint b/.local/secondary_skills/branding-generator/.fingerprint new file mode 100644 index 0000000..cd756c6 --- /dev/null +++ b/.local/secondary_skills/branding-generator/.fingerprint @@ -0,0 +1 @@ +7b0c07bdd42ea2cdbf219d62302948c2 \ No newline at end of file diff --git a/.local/secondary_skills/branding-generator/SKILL.md b/.local/secondary_skills/branding-generator/SKILL.md new file mode 100644 index 0000000..e9ff9e4 --- /dev/null +++ b/.local/secondary_skills/branding-generator/SKILL.md @@ -0,0 +1,286 @@ +--- +name: branding-generator +description: Create brand identity kits — logos, color palettes, typography, naming, and style guides. +--- + +# Branding Generator + +Create brand identity kits. Interview the user, research the space, then deliver 3 distinct brand directions with visual assets. + +## When to Use + +- "I need branding / a brand identity / brand kit" +- "I need a logo" / "design me a logo" + +- "What colors should I use?" / "help me pick colors" +- "What fonts should I use?" / "help me choose typography" + +- "I need a style guide" / "brand guidelines" / "brand book" / "brand assets" +- "I need a visual identity" / "design system" + +- "Help me name my company / app / product" +- "I'm starting a new business/product" (early-stage founders needing naming + identity) + +- "Make my app look more professional" / "my app looks generic" (signals a visual identity gap) +- Color palettes, typography, visual identity from scratch + +- Rebranding or brand refresh +- Brand naming + +## When NOT to Use + +- Full UI design (use design skill) Ā· Slide decks (use slides skill) + +## Step 1: Brand Interview + +Conduct this like a real branding agency discovery session. Ask these questions **conversationally, not as a wall of text** — adapt based on answers, ask follow-ups, go deeper where it matters. Group into 2-3 messages max. + +### Round 1 — The Business + +- What does your company/product do, in one sentence? +- Who is your target audience? (Be specific — age, role, lifestyle, not just "everyone") + +- What problem do you solve that nobody else does? +- What's your pricing position? (Budget / mid-market / premium / luxury) + +- **Do you already have a name, or do you need naming help?** + +### Round 2 — The Feeling + +- Name 3 brands you admire (any industry) and what you admire about them +- If your brand were a person, how would they dress? How would they speak? + +- What emotions should someone feel when they see your brand for the first time? +- What's the one word you'd want people to associate with you? + +- Any colors, styles, or aesthetics you absolutely hate? + +### Round 3 — Practical Constraints + +- Do you have any existing brand assets (logo, colors, fonts) you want to keep? +- Where will this brand primarily live? (Web app, mobile app, physical product, social media, print) + +- Any industry conventions you need to follow — or deliberately break? +- Competitor URLs or screenshots? (If provided, extract their palettes with colorthief for contrast analysis) + +### Round 4 — Brand Touchpoints + +- What is the **single most important touchpoint** for your brand? (e.g., mobile app icon, website hero, packaging, storefront, email newsletter, social media profile) +- List 3-5 specific contexts where people will encounter your brand (e.g., "app store listing", "trade show banner", "Instagram stories", "invoice PDF", "product unboxing") + +- Which of these touchpoints is the first impression for most users? + +Prioritize the most important touchpoints when building mockups in Step 5. The "Brand in Action" board should focus on the touchpoints the user actually cares about, not generic website pages. + +**Do not proceed until you have solid answers.** Push back if answers are vague — "everyone" is not a target audience, "clean and modern" is not a personality. + +## Step 2: Research + +After the interview, do targeted research before generating directions: + +- **Competitor visual audit** — Search for 3-5 competitors' visual identities. Extract their color palettes, typography, and logo styles. Present a side-by-side summary of what's common in the space so the new brand can visually stand apart — not just conceptually, but with measurable color distance. +- **Mood/reference gathering** — Search for visual references matching the interview answers (e.g., "minimalist premium SaaS branding", "bold playful fintech design"). + +- **Industry conventions** — What do users in this space expect? Where is there room to stand out? + +## Step 2.5: Brand Naming (if needed) + +If the user doesn't have a name, generate name candidates as part of each brand direction. For each direction, propose 2-3 name options. + +### Naming criteria + +- **Memorable** — short (ideally 1-2 syllables, max 3), easy to say and spell +- **Distinctive** — doesn't sound like existing competitors in the space + +- **Meaningful** — connects to the brand concept, even if abstractly +- **Domain-friendly** — check `.com`availability via`webSearch("site:instantdomainsearch.com [name]")` or similar + +- **Social-friendly** — the name should work as a handle (@name) on major platforms + +#### Name generation approaches + +1. **Portmanteau** — blend two relevant words (e.g., Pinterest = Pin + Interest) +2. **Action verb** — conveys what the product does (e.g., Grab, Snap, Dash) + +3. **Abstract/invented** — coined word that sounds right (e.g., Spotify, Figma) +4. **Real word, new context** — existing word reframed (e.g., Slack, Notion, Linear) + +5. **Foreign/multilingual** — borrow from another language for freshness + +Present names alongside each direction so the name and visual identity feel cohesive. + +## Step 3: Generate 3 Brand Directions + +**Always present exactly 3 distinct directions.** Each should feel like a different creative team's pitch — not slight variations. + +For each direction, provide: + +1. **Brand name**(if naming)**& concept narrative** — 1-2 sentence strategic thinking behind this direction +2. **Color palette** — primary, secondary, accent with hex + OKLCH values. Include neutral scale (50-900) tinted toward the primary hue. Verify WCAG AA contrast for all text/background pairs. + +3. **Typography** — display + body font pairing from Google Fonts with rationale +4. **Voice** — 3-5 adjectives defining how the brand speaks, plus copy examples across multiple contexts: + +- An example **headline** (marketing/hero) +- An example **onboarding welcome message** (first-time user greeting) + +- An example **error message** (something went wrong) +- An example **empty state message** (no data yet) + +- An example **call-to-action** (button or prompt) + +These examples make the voice tangible and testable — abstract adjectives alone are not enough. + +1. **Visual mood** — overall aesthetic description (photography style, illustration approach, texture usage). Reference 2-3 real-world brands that share elements. +2. **Exportable tokens** — provide CSS custom properties and Tailwind config alongside each direction (not just at the end) so developers can start experimenting immediately: + +```css + +/* Direction A tokens */ + +--primary: \#1A1A2E; + +--primary-oklch: oklch(18% 0.02 270); + +--accent: \#D4A855; + +--background: \#F5F0EB; + +``` + +```js + +// Tailwind extend + +colors: { + +primary: { 50: '...', 100: '...', /* ... */ 900: '...' }, + +accent: { 50: '...', /* ... */ 900: '...' } + +} + +``` + +## Step 4: User Picks a Direction + +Present all 3 and ask the user to pick one or mix elements. Use structured prompts to make mixing easier: + +- "Which **name** resonates most?" +- "Which **color palette** feels right for your brand?" + +- "Which **voice/tone** matches how you want to speak to users?" +- "Which **visual mood** would you want your product to feel like?" + +The user can pick Direction A's name with Direction B's colors and Direction C's tone — facilitate that mixing explicitly. Don't proceed to assets until they approve a direction (or hybrid). + +## Step 4.5: Refine the Chosen Direction + +Before building the full brand kit, offer a focused refinement round on the selected (or hybrid) direction. Present the consolidated direction summary and ask: + +- "Would you like the palette **warmer or cooler**? Lighter or darker overall?" +- "Should the typography feel **heavier/bolder**or**lighter/more refined**?" + +- "Is the voice **too formal, too casual, or just right**?" +- "Any specific element from the other directions you'd still like to pull in?" + +Apply requested tweaks and present the updated direction for final approval. This avoids costly rework after the full kit is built. Limit to **2 refinement rounds max** — if the user is still unsure after two rounds, recommend proceeding and iterating on the finished boards where changes are easier to visualize. + +## Step 5: Deliver the Brand Kit + +Once a direction is approved, **delegate to the design subagent** (`subagent`with`specialization="DESIGN"`) to build polished visual boards. Embed them as iframes on the canvas. + +### Deliverables + +**Board 1 — Color & Typography:** Color swatches with hex + OKLCH values, shade ramps (50-900), typography specimen at heading/body/caption sizes with Google Fonts loaded, contrast audit table, dark mode variant. + +**Board 2 — Logo Concepts:**3-4 logo variations (wordmark, icon+text, icon-only, monogram) built as**inline SVG**. Show on light and dark backgrounds at multiple sizes (large display + 32px favicon size). Include SVG source for export. + +Logo quality checklist: + +- Every logo must be **recognizable at 32px** (favicon/app icon test) +- Include a **single-color version** for monochrome contexts (printing, embossing, watermarks) + +- Test on **both light and dark backgrounds** — the logo must work on both without modification or with a simple color inversion +- Use **geometric simplicity** — avoid fine details that collapse at small sizes + +- Provide the icon in a **rounded-square container** variant for app store / social profile use + +**Board 3 — Brand in Action:**Realistic mockups showing the brand applied to the**user's actual product type**, not generic pages. If the user is building a marketplace, show a listing card, search results, and app header. If they're building a SaaS dashboard, show the dashboard. Match the mockups to what they're actually building. This board should feel like seeing their real product with the new brand applied. + +**Board 4 — Brand Guidelines:** Color usage rules, typography hierarchy, voice & tone guidelines, 1-2 sample applications (business card, social post). + +### Accessibility Checklist + +Every brand kit must address accessibility beyond just color contrast: + +- **Minimum font sizes** — body text no smaller than 16px on web, 14px on mobile. Captions no smaller than 12px. +- **Touch target sizing** — interactive elements must be at least 44x44px (iOS) / 48x48dp (Android). Specify this in the guidelines so designers don't shrink branded buttons below usable sizes. + +- **Motion sensitivity** — if the brand identity includes animations or transitions, provide a `prefers-reduced-motion` alternative. Note which brand animations are decorative (can be removed) vs. functional (must be preserved in reduced form). +- **Font legibility** — verify that the chosen display and body fonts remain legible at the specified minimum sizes. Decorative display fonts must not be used for body copy or UI labels. + +- **Icon clarity** — any branded iconography must be distinguishable at 24px and not rely solely on color to convey meaning. + +Include these standards in Board 4 (Brand Guidelines) as a dedicated "Accessibility Standards" section. + +### Export & Deliverable Formats + +Before building the final kit, ask the user which export formats they need. Present as a checklist: + +- **Design tokens** — CSS custom properties, Tailwind config, SCSS variables (included by default) +- **Asset package** — ZIP containing logo SVGs, PNG exports at 1x/2x/3x, favicon ICO/PNG, and Open Graph image (1200x630) + +- **Social media templates** — dimensions and safe zones for Instagram post (1080x1080), Instagram story (1080x1920), X/Twitter header (1500x500), LinkedIn banner (1584x396) +- **Print-ready files** — CMYK color values, bleed specifications, business card layout (3.5x2in) + +- **Brand book PDF** — a single-document summary of all guidelines, suitable for sharing with external vendors or team members + +Generate the formats the user selects. At minimum, always deliver design tokens and the asset package. + +## Step 5.5: Domain & Social Handle Check + +After the user approves a direction and name, verify availability: + +- **Domain**: Search for `.com`,`.co`,`.app`,`.io` availability +- **Social handles**: Check `@name` availability on major platforms via web search (Instagram, TikTok, X/Twitter) + +- **Trademark conflicts**: Quick web search for existing trademarks in the same industry + +Present findings clearly: + +```text + +Name: SWAPD + +- swapd.com — āŒ taken +- swapd.co — āœ… available + +- swapd.app — āœ… available +- @swapd (Instagram) — āŒ taken + +- @getswapd (Instagram) — āœ… available +- @swapd (TikTok) — āœ… available + +``` + +If the primary domain or key handles are taken, suggest variations (get-, try-, use- prefixes, or alternate TLDs) before the user commits. + +## Color Science + +- Work in OKLCH color space (perceptually uniform — same L = same perceived lightness across hues) +- Use color harmony from OKLCH hue space: complementary (H+180°), analogous (H±30°), triadic (H±120°), split-comp (H+150°/H+210°) + +- Generate shade ramps by stepping L linearly in OKLCH — avoids the muddy-middle problem of RGB interpolation +- WCAG 2.2 AA: 4.5:1 contrast for normal text, 3:1 for large text and UI components + +- Use chroma-js or apcach for programmatic contrast verification +- Dark mode: backgrounds at `oklch(15-20% 0.01 H)` not pure black. Desaturate brand colors slightly (reduce C by ~0.02). + +## Limitations + +- Logo concepts are starting points — final production logos should be refined with a dedicated designer +- Fonts limited to Google Fonts / open-source unless user provides custom fonts + +- Domain/handle availability checks are point-in-time — availability can change; register quickly once decided +- Trademark search is a surface-level web check, not a legal opinion — recommend a proper trademark search for high-stakes brands diff --git a/.local/secondary_skills/competitive-analysis/.fingerprint b/.local/secondary_skills/competitive-analysis/.fingerprint new file mode 100644 index 0000000..bfb5633 --- /dev/null +++ b/.local/secondary_skills/competitive-analysis/.fingerprint @@ -0,0 +1 @@ +0e0d062aa0d44b32ff73211909c25f5f \ No newline at end of file diff --git a/.local/secondary_skills/competitive-analysis/SKILL.md b/.local/secondary_skills/competitive-analysis/SKILL.md new file mode 100644 index 0000000..31a1109 --- /dev/null +++ b/.local/secondary_skills/competitive-analysis/SKILL.md @@ -0,0 +1,429 @@ +--- +name: competitive-analysis +description: Perform competitive market analysis with comparisons and strategic recommendations. +--- + +# Competitive Analysis + +Identify competitors, analyze positioning, and deliver actionable recommendations. Skip textbook frameworks (Porter's, PESTLE) unless specifically requested — they're MBA artifacts, not operator tools. + +## When to Use + +- "Who are my competitors?" / "How do we compare to X?" +- Feature comparison matrix or positioning map needed + +- Fundraising deck competition slide +- Finding market gaps + +## When NOT to Use + +- General market sizing (use deep-research) +- SEO-specific competitor keyword analysis (use seo-auditor) + +## What Practitioners Actually Use + +Skip Porter's Five Forces. Operators use these four: + +**1. April Dunford's Positioning (from "Obviously Awesome")** — the most-used positioning method in B2B SaaS. Five inputs in strict order: + +1. Competitive alternatives (what customers would do if you didn't exist — including "spreadsheets" and "nothing") +2. Unique attributes you have that alternatives lack + +3. Value those attributes deliver (with proof) +4. Best-fit customer characteristics + +5. Market category you win in + +Key insight: positioning starts from *alternatives*, not features. Your "competitor" might be Excel. + +**2. Wardley Mapping** (Simon Wardley, free book at medium.com/wardleymaps) — plot components on two axes: visibility-to-user (y) vs evolution Genesis → Custom → Product → Commodity (x). Reveals: where competitors overinvest in commoditizing components, where to build vs buy, what's about to become table stakes. Tool: onlinewardleymaps.com (free). Best for platform/infra competition. + +**3. Feature comparison matrix** — the unglamorous workhorse. Rows = capabilities, columns = competitors, cells = āœ“/āœ—/partial. Battlecards for sales teams are this + "trap-setting questions." Key: weight features by how often they appear in lost-deal notes, not by what engineering thinks matters. + +**4. Kano mapping applied to competitors** — categorize each competitor feature as Basic (expected, table stakes), Performance (more = better), or Delighter (unexpected). Kano's insight: today's delighters become tomorrow's basics. Competitors' delighters tell you where the bar is moving. + +## Research Toolchain + +| Need | Tool | How to use | + +|---|---|---| + +| Find competitors | `webSearch("[product] alternatives site:g2.com")` | G2's "alternatives" pages are crowdsourced competitor lists | + +| Verified user complaints | `webSearch("[competitor] site:g2.com")`, Capterra, TrustRadius | Filter reviews to 1-3 stars. Look for repeated phrases — those are exploitable weaknesses | + +| Enterprise IT buyers | PeerSpot (formerly IT Central Station) | More technical, less marketing-gamed than G2 | + +| Pricing (often hidden) | `webFetch`competitor /pricing page, Wayback Machine for historical,`webSearch("[competitor] pricing reddit")` for leaked enterprise quotes | | + +| Tech stack | `webFetch("https://builtwith.com/[domain]")` — 673M+ sites, 85k+ technologies. Wappalyzer similar. | Reveals: are they on legacy stack? What vendors? Switching cost signals | + +| Traffic/channel mix | SimilarWeb (reliable for large sites, unreliable <50k visits/mo) | See which channels drive competitor traffic | + +| Funding/team size | Crunchbase free tier, `webSearch("[competitor] raises TechCrunch")` | | + +| Strategic direction | `webSearch("[competitor] site:linkedin.com/jobs")` — hiring = roadmap. 5 ML engineers = AI features in 6mo. | | + +| Historical messaging | `webFetch("https://web.archive.org/web/2024*/[competitor].com")` | Shows positioning pivots — what they tried and abandoned | + +| SEO/content strategy | Ahrefs (paid, $129+/mo) or `webSearch("site:[competitor].com")` to map content | | + +| Regional competitors (non-US) | App Store: `curl -sL "https://apps.apple.com/us/search?term=[name]"`Ā· Play Store:`webSearch("[name] site:play.google.com")` Ā· Search in local language | G2/Product Hunt have near-zero coverage outside US/EU | + +### Analyzing JS-Rendered Competitor Sites (SPAs) + +Many early-stage competitors build their site as a React/Vue/Svelte SPA. `webFetch`and`webSearch`return empty results for these — the HTML shell has nothing but`
`. **Always try`curl` via bash first:** + +#### Step 1 — Get meta tags from the HTML shell (works even on SPAs) + +```bash + +curl -sL --max-time 10 "https://competitor.com/" | head -100 + +# → Reveals: title, meta description, OG tags, and the JS bundle filename + +``` + +##### Step 2 — Extract readable strings from their JS bundle + +```bash + +# Get the bundle filename from Step 1 output (e.g. /assets/index-AbCd1234.js), then: + +curl -sL "https://competitor.com/assets/index-[hash].js" \\ + +| grep -oE '"[^"]{10,200}"' \\ + +| grep -iE "(price|plan|free|gratis|feature|bank|sync|categor|budget|presupuest)" \\ + +| sort -u | head -80 + +``` + +###### Step 3 — Check static files for site structure + +```bash + +curl -sL "https://competitor.com/robots.txt" + +curl -sL "https://competitor.com/sitemap.xml" + +curl -sL "https://competitor.com/manifest.json" + +``` + +This approach can reveal pricing plans, feature descriptions, FAQ content, legal disclaimers, and marketing copy — all embedded in the compiled JS. For example, this technique on `novia.com.do` surfaced: their two pricing tiers ("Plan Cita" = free, "Plan Compromiso" = premium coming soon), their exact value proposition copy, a disclaimer that they have no real-time bank connection, and their full FAQ structure. + +## Critical Rule: When the User Names a Specific Competitor + +**If the user tells you a competitor exists by name, believe them immediately.** Do not attempt to verify through web searches first — that costs multiple failed rounds. Instead: + +1. **Ask for the URL right away** if you don't already have it: *"Can you share their website or App Store link?"* +2. **Once you have a URL**, go directly to the SPA research chain (curl → bundle extraction) — do not webFetch or webSearch the name first. + +3. **If you have no URL and searches return nothing**, ask the user for 3–5 key facts: what it does, price, platform, 1–2 differentiators. User knowledge > empty search results every time. + +The user naming a competitor is the highest-confidence intelligence you will receive. Don't waste rounds trying to independently confirm what they already know. + +## Zero Search Results Protocol + +When `webSearch`and`webFetch` both return empty results for a competitor, follow this decision tree in order — **do not repeat the same failed approach with different keywords:** + +1. **Try curl on the homepage** (catches SPA meta tags — see SPA section below) +2. **Try curl on their JS bundle** (catches pricing, features, copy — see SPA section) + +3. **Try App Store / Play Store** — search `apps.apple.com`and`play.google.com` directly for the app name; the store listing contains descriptions, screenshots text, and reviews +4. **Try social proof search** — `webSearch("[name] instagram OR twitter OR linkedin")` — even tiny startups have social profiles + +5. **Ask the user** — if all above fail, ask for 3–5 facts and build the profile from that. State clearly: *"I can't find [name] through any of my research tools. Can you tell me what they do, their price, and their main features?"* + +**Empty results ≠ no competition.** In niche, regional, or non-English markets (Latin America, Caribbean, Southeast Asia, MENA), G2/Capterra/Product Hunt have near-zero coverage. An app can have 10,000 active users and zero English web presence. + +## Niche and Regional Market Research + +Standard tools (G2, Capterra, Product Hunt) are US/English-centric. For non-US markets use these instead: + +| Market type | Where to look | + +|---|---| + +| Latin America | App Store regional search (`apps.apple.com/[country-code]/`), Google Play with`hl=es`, local tech blogs (Contxto, Startup Genome LatAm), AppFollow for store rankings | + +| Caribbean / Emerging | Instagram/Facebook pages (startups in these markets often exist only on social), local chambers of commerce, fintech-specific databases (Finnovista, IDB Fintech census) | + +| Any niche market | Search in the local language — always try Spanish/Portuguese/French/etc. queries, not just English. A Dominican app will not appear in English results. | + +| App stores (universal) | `curl -sL "https://apps.apple.com/[country]/search?term=[query]"` and Play Store search — app descriptions contain features and positioning that web searches miss | + +**Rule:** Always run at least one search in the target market's primary language before concluding no local competitors exist. + +## Methodology + +**Step 1: Frame** — Get from user: their product, target customer, and who THEY think competes. Their list is always incomplete — but treat every name they give you as a confirmed lead, not a hypothesis to verify. + +**Step 2: Expand the competitor set** — Run `webSearch("[known competitor] alternatives")`and`webSearch("[category] vs")`. Check G2 category pages. Add indirect competitors (different product, same job) and the "do nothing" option. **Also search in the local market language** if the product targets a non-English market. + +**Step 3: Per-competitor dossier** — For each (limit to 5-7 for depth): + +- Positioning one-liner (their homepage H1 or title tag) +- Pricing model + tiers (try /pricing; if SPA use curl; if nothing found, note it explicitly) + +- Top 3 strengths (from 5-star reviews, or inferred from their own copy if no reviews exist) +- Top 3 weaknesses (from 1-2 star reviews — use exact customer language; if no reviews, infer from what they don't mention) + +- Funding stage + headcount (Crunchbase/LinkedIn) +- Recent product launches (changelog, blog, Product Hunt) + +**If a competitor is a direct local rival** (same market, same core use case, same pricing model): flag them separately as "Direct Competitor" and add a dedicated head-to-head comparison section — don't just include them as one row in the matrix. Make clear: *what does the user's product do that this one doesn't, and vice versa?* + +**Step 4: Synthesize** — Build the feature matrix. Plot on a 2Ɨ2 (pick the two axes the *buyer* cares about, not the ones that make user look good). Identify white space. + +**Step 5: Recommend** — Not "monitor the threat." Specific: "Competitor X's reviews mention slow support 23 times — lead with your SLA in sales calls." + +## Ongoing Monitoring + +Competitive landscapes shift constantly — pricing changes, features launch, funding rounds close. The analysis you just delivered is a snapshot. This section defines monitoring as a **second deliverable** the agent offers immediately after the report, not optional advice. + +### Always Offer Monitoring Activation + +At the end of every competitive analysis, **always** ask: + +> *"Would you like me to set up ongoing monitoring for these competitors? I'll generate your alert links, a bookmark bundle, and a monthly ritual checklist — takes about 2 minutes to activate. Where do you want alerts to land?"* + +Do not skip this offer. Present it as a distinct, activatable package — not a footnote. + +### Channel Decision Tree + +Ask the user which channel they prefer, then follow the matching setup path. Priority order: **Slack → Teams → Email → Manual file**. + +```text + +Does the user have Slack? + +YES → Set up Slack RSS feeds + optional webhook + +NO → Does the user work in a Microsoft org (Teams)? + +YES → Set up Teams RSS connector + +NO → Set up Google Alerts (email) + +Always: also save competitor-monitoring.md to the project regardless of channel chosen. + +``` + +If the user is unsure or doesn't answer, default to **Google Alerts** (zero-friction, universally available) plus the project file. + +### Per-Channel Setup Instructions + +#### Slack + +##### Option A — RSS feeds (native, free, no admin required) + +```text + +/feed subscribe https://[competitor].com/changelog/rss + +/feed subscribe https://[competitor].com/blog/rss + +``` + +Run these commands in a dedicated `#competitive-intel` channel. The agent should generate the exact feed URLs for each competitor and give the user the ready-to-paste commands. + +###### Option B — Google Alerts → Slack (via Zapier or Make, free tier) + +1. Create a Gmail label called "Competitor Alerts" (for each Google Alert) +2. In Zapier/Make: Trigger = new email with label "Competitor Alerts" → Action = post message to `#competitive-intel` + +3. The agent provides exact Zapier/Make setup steps when this option is chosen + +###### Option C — Incoming webhook (advanced) + +When the user runs the monthly ritual on demand, the agent can post a summary to a Slack webhook URL. The user provides the webhook URL; the agent stores it in the monitoring brief for future use. + +#### Microsoft Teams + +##### RSS connector (native, free) + +1. Open the target channel → click `...` → Connectors → RSS +2. Paste the feed URL and set a display name + +3. The agent generates the exact feed URLs for each competitor's changelog and blog + +###### Power Automate (for Microsoft 365 orgs) + +Trigger: new email matching subject pattern → Post message in Teams channel. The agent describes the exact flow when this option is chosen. + +#### Google Alerts (Email — universal fallback) + +For each competitor, generate a ready-to-click alert URL: + +```text + +https://www.google.com/alerts?q=[COMPETITOR+NAME]&hl=en&gl=us&source=web&hl=en + +``` + +Replace `[COMPETITOR+NAME]` with the URL-encoded competitor name. The user clicks once to activate. Recommend setting delivery to "As it happens" for major competitors, "At most once a week" for minor ones. + +Also generate alerts for: `"[competitor] pricing"`,`"[competitor] raises"`,`"[competitor] launches"`. + +#### Manual Project File (always generated) + +Regardless of which channel is chosen, always save a `competitor-monitoring.md` file to the project root. This file is the source of truth and last-checked log. Structure: + +```markdown + +# Competitor Monitoring Brief + +Last updated: [date] + +## Competitors tracked + +- [Name] — [URL] — Alert channel: [Slack/#channel | Teams/#channel | Email] + +## Bookmark bundle + +Per competitor: pricing page, changelog/blog, App Store listing, LinkedIn jobs, G2 reviews page + +## Change log + +| Date | Competitor | What changed | Action taken | + +|------|------------|-------------|--------------| + +``` + +### The Monitoring Package Deliverable + +When the user activates monitoring, the agent generates and delivers four items: + +1. **Alert bundle** — ready-to-click Google Alert URLs (or paste-ready Slack/Teams commands), one set per competitor +2. **Bookmark list** — 5 URLs per competitor: pricing page, changelog or blog, App Store listing, LinkedIn jobs, G2/Capterra reviews page + +3. **Ritual card** — the 30-minute monthly checklist (see below), saved to `competitor-monitoring.md` +4. **On-demand command** — a natural language prompt the user can paste back at any time: *"Run my monthly competitive check for [competitor name]"* — the agent then runs the ritual and updates the monitoring brief + +### 30-Minute Monthly Ritual + +A structured, timed sequence the user (or agent, on demand) runs once per month per competitor: + +| Minutes | Task | What to look for | + +|---|---|---| + +| 0–5 | Check Google Alert digest (or Slack/Teams channel) | Any press coverage, blog posts, or product announcements since last month? | + +| 5–10 | Open App Store listing | Any version updates? Read the 3 most recent reviews for new complaint patterns | + +| 10–15 | Open their changelog or blog | Any feature launches? Note the category (pricing, UX, integrations, AI) | + +| 15–20 | Scan their jobs page | Any new roles? 3+ ML/AI roles = AI feature coming. Enterprise Sales hire = moving upmarket | + +| 20–25 | Check pricing page (compare to Wayback Machine if needed) | Any tier changes, price increases, or new plan names? | + +| 25–30 | Update `competitor-monitoring.md` | Log date + what changed. Flag anything that warrants a response | + +**Output of each ritual:** one row added to the change log in `competitor-monitoring.md`. If a change is significant (new pricing tier, major feature launch, funding round), escalate: *"[Competitor] launched [X] — this affects [specific recommendation from the original report]. Consider [specific response]."* + +### On-Demand Ritual Invocation + +The user can trigger the ritual at any time by telling the agent: + +> *"Run my monthly competitive check for [competitor name]"* +> +> *"What's changed with [competitor] since last month?"* +> +> *"Update my competitive monitoring"* + +The agent reads `competitor-monitoring.md` to get the last-checked date and bookmark list, runs through the ritual checklist, and appends findings to the change log. + +## Output — Ask the User First + +Before building any deliverable, **ask the user how they want the analysis presented** using the query tool: + +> "How would you like your competitive analysis presented — as a **slide deck**or a**written report**?" + +Then follow the appropriate path below. Do not default to one format without asking. + +--- + +### Option A: Slide Deck + +**Load the `slides` skill** and build a Replit slide deck. Follow the slides skill's conventions for manifest, components, and design. Structure the deck as: + +1. **Title slide** — Product name, category, date +2. **Executive summary** — Positioning statement (Dunford format) + top 3 recommendations + +3. **Competitive landscape** — Table: Company, Stage, Pricing, Strength, Weakness +4. **Feature matrix** — Rows = capabilities, columns = competitors, cells = checkmark/x/partial, color-coded + +5. **Positioning map** — 2Ɨ2 chart (matplotlib/plotly image) +6. **White space & opportunities** — Gaps + Kano analysis + +7. **Action plan** — Top 3 specific actions + battlecard trap-setting questions +8. **Sources** — Numbered URLs for every claim + +--- + +### Option B: Written Report (PDF + Web Preview) + +**Do not output a markdown summary.**Build a polished competitive analysis report as a professional PDF using**jsPDF**, with a React web preview that visually matches page-by-page. The report should look like a strategy consulting deliverable. + +**Build order:** Generate the PDF first and present it to the user. Then build the web preview. The PDF is the primary deliverable — the web app is a visual complement. + +#### Report Structure + +1. **Page 1 — Executive Summary:** Product name, category, date. Positioning statement (Dunford format): For [target customer] who [need], [product] is a [category] that [key benefit]. Unlike [primary alternative], we [key differentiator]. Top 3 strategic recommendations (the "so what"). +2. **Page 2 — Competitive Landscape:** Table with Company, Stage, Pricing, Strength (from reviews), Weakness (from reviews). Funding/headcount context for each competitor. + +3. **Page 3 — Feature Matrix:** Rows = capabilities, columns = competitors, cells = checkmark/x/partial. Weight column (1-5) based on buyer conversation frequency. Color-code: green where the user's product wins, red where it loses. +4. **Page 4 — Positioning Map:** 2x2 chart with axes based on buyer decision criteria (not vanity metrics). Each competitor plotted with logo or labeled dot. Generated via matplotlib or plotly, embedded as image. + +5. **Page 5 — White Space & Opportunities:** Gaps no one serves well, with evidence from reviews and market data. Kano analysis: which competitor features are Basics vs Performance vs Delighters. +6. **Page 6 — Action Plan:** Top 3 specific actions with source citations. Battlecard-style "trap-setting questions" for sales calls. + +7. **Final Page — Sources:** Numbered URLs for every claim. + +#### PDF Generation (jsPDF) + +Use **jsPDF** to generate the PDF with explicit point-based layout: + +- `new jsPDF({ unit: "pt", format: "letter" })` — US Letter: 612Ɨ792pt +- Use 36pt margins (0.5in). Content area: 540w Ɨ 720h points. + +- **Track Y position** as you render each element. When the next element would exceed `PAGE_H - MARGIN`, call`doc.addPage()` and reset Y to the top margin. Never let content silently overflow — always check before rendering. +- Embed charts as images via `doc.addImage()` — scale to fit content width while respecting remaining page height. + +- Add a **header**and**footer**on each page.**Footer must save/restore Y position** — do not let footer drawing move the content cursor, or subsequent content will force blank pages. +- Before any manual page break, check whether a fresh page was already added (track an `isNewPage` flag). Only add a page if you're not already on a fresh one. + +- **Required before presenting:** After generating the PDF, verify there are no blank pages. If any page is blank, fix the page-break logic and regenerate. + +#### Web Preview + +The React web artifact renders the same report data as an HTML version that **visually mirrors the PDF page-by-page**. Each "page" should be a fixed-size container (816Ɨ1056px — US Letter at 96dpi) with the same margins, typography, and chart placement as the PDF. + +## Honesty Rules + +- If the user's product loses on most dimensions, say so — then find the niche where they win +- "No competitors" is never true. The competitor is always at least "build it yourself" or "do nothing" + +- Flag when data is thin (e.g., "SimilarWeb shows <50k visits — estimate is low-confidence") +- Cite every claim to a URL the user can verify + +- **Flag inferred data:** if a competitor profile was built from JS bundle strings or user-provided facts (not reviews or public docs), say so: *"Profile based on homepage copy and compiled JS — no independent reviews available."* +- **Zero search results is not the same as no competitor.** If searches return nothing for a named competitor, say: *"I couldn't find [name] in any public database — this likely means they have low SEO footprint, not that they don't exist."* + +## Limitations + +- G2/Capterra reviews skew toward mid-market SaaS; thin for enterprise and consumer +- SimilarWeb is inaccurate for sites under ~50k monthly visits + +- Cannot access paid CI tools (Klue, Crayon, Kompyte) or PitchBook +- Pricing pages lie — enterprise pricing is almost never public + +- **webFetch and webSearch fail for:** JS-rendered SPAs (use curl), social media URLs (LinkedIn, Instagram, Twitter — blocked by robots), sites behind Cloudflare or login walls, and any product with <1k English web mentions +- **Regional/emerging market blind spot:** G2, Product Hunt, Crunchbase have minimal coverage of LatAm, Caribbean, SEA, MENA, and African markets. Local competitors in these markets will often have zero results in standard research tools — always fall back to local-language search, App Store regional search, and direct curl analysis + +- **Monitoring channel assumptions:** Slack RSS setup requires the native Slack RSS app to be installed in the workspace (free, but needs a workspace admin in some orgs). Teams RSS connector requires a Teams channel with Connectors enabled. If neither is available, fall back to Google Alerts → email without requiring any third-party tools or admin permissions. diff --git a/.local/secondary_skills/content-machine/.fingerprint b/.local/secondary_skills/content-machine/.fingerprint new file mode 100644 index 0000000..daff160 --- /dev/null +++ b/.local/secondary_skills/content-machine/.fingerprint @@ -0,0 +1 @@ +bb932526514e851f7ef5dd274ce364b1 \ No newline at end of file diff --git a/.local/secondary_skills/content-machine/SKILL.md b/.local/secondary_skills/content-machine/SKILL.md new file mode 100644 index 0000000..b4c4697 --- /dev/null +++ b/.local/secondary_skills/content-machine/SKILL.md @@ -0,0 +1,321 @@ +--- +name: content-machine +description: Create social media posts, newsletters, and marketing content across platforms. +--- + +# Content Machine + +Create social posts, newsletters, and marketing copy that respects platform mechanics — truncation points, algorithm signals, and hook physics — not just "good writing." + +## When to Use + +- Social posts (X/Twitter, LinkedIn, Instagram feed, Instagram Stories, TikTok captions, Threads) +- Writing captions for social media posts + +- Writing hooks for posts and content +- Newsletters, blog posts, content calendars, cross-platform repurposing + +- Content repurposing ("turn this into multiple posts", "repurpose this blog post") +- Social media strategy and content planning + +## When NOT to Use + +- Cold outreach (cold-email-writer) Ā· Paid ad copy (ad-creative) Ā· Research reports (deep-research) Ā· SEO audits (seo-auditor) + +## Step 1: Voice Analysis + +Ask for 3-5 existing posts. Extract: avg sentence length, contraction usage, emoji density, POV (I/we/you), signature phrases. If none exist, ask for 2 creators they want to sound like and use `webFetch` to pull recent posts as voice reference. + +## Step 2: Platform Mechanics (2025-2026 Specs) + +### LinkedIn — 3,000 char max, but truncation is what matters + +- **"...see more" cutoff: ~140 chars desktop, ~110 chars mobile.** 57%+ of LinkedIn traffic is mobile — write the hook for 110 chars. +- **Algorithm weights:** comments count ~2x likes; dwell time is a primary signal; first 60-120 min engagement velocity determines reach ceiling. + +- **Optimal length:** 800-1,000 chars (not 3,000). Short paragraphs (1-2 lines) + white space increase dwell time. +- **Structure:** Hook (110 chars, no throat-clearing like "I wanted to share...") → story/insight → single question CTA. Reply to every comment in the first hour to extend the test window. + +- **Hashtags:** 3-5 max, at the very end. LinkedIn deprioritized hashtag discovery. + +### X/Twitter — 280 chars (free), 25,000 chars (Premium) + +- Long posts on Premium truncate at ~280 chars in the feed — the hook rule still applies. +- **Thread structure:** Tweet 1 = the full promise ("How I went from X to Y in Z — thread 🧵"). Each tweet must stand alone for retweets. Last tweet = CTA + loop back to tweet 1. + +- Line breaks double engagement vs. wall-of-text. + +### Instagram Feed — 2,200 char caption, ~125 chars visible before "...more" + +- **Hashtags: 3-5, not 30.** Instagram's @creators account officially reversed the old advice; 20+ hashtags now reads as spam and can suppress reach. Put them inline or at the end, not in a comment. +- First line = hook. Emoji as bullet points scan faster than dashes on mobile. + +- Format: Square (1080Ɨ1080) or portrait (1080Ɨ1350, 4:5 — outperforms square on CTR). + +### Instagram Stories — 1080Ɨ1920, 9:16 + +Stories are a fundamentally different medium from feed posts. Treat them as such. + +#### Key differences from feed + +- Stories are **ephemeral and sequential** — viewers tap through in 2-3 seconds. There is no caption to read. The visual *is* the entire message. +- Stories are better for **two-way interactions** (polls, questions, DMs) than for broadcasting. + +- Feed posts have copy doing the heavy lifting. Stories must work without it. + +##### Safe zones — mandatory + +| Zone | Range | Why | + +|---|---|---| + +| Top dead zone | Top 14% (~270px) | Profile name, mute, close button UI | + +| Bottom dead zone | Bottom 20% (~380px) | "Send message" bar + swipe-up area | + +| **Safe core**|**14% – 80% from top** | All content must live here | + +Never place any text, logo, CTA, or key visual outside the safe core. + +###### Story formats by content type + +| Content angle | Best story format | Why | + +|---|---|---| + +| Pain point | Single frame, stripped to one-liner | Needs immediate gut impact — no room for buildup | + +| Educational | Poll (two-option) | Polls get 3Ɨ more taps than passive stories; drives return for "reveal" | + +| Feature/product | 3-frame sequence: Problem → Solution → Result | Complex message needs beats; tap-through is an algorithm signal | + +| Relationship/split concept | Vertical split visual | 9:16 is naturally tall — a top/bottom split reads instantly | + +| Tips list | One tip per frame (e.g., "Tip 1 de 3") | Breaks up information; each frame drives tap-through to next | + +###### Story copy rules + +- Strip feed copy to its absolute core. One line, not a paragraph. +- The hook becomes the entire visual headline — make it 9-12vw on screen and impossible to miss. + +- CTAs live in the bottom safe zone (72-78vh) as a full-width strip or pill — not scattered across the frame. +- Progress indicators ("1 / 3", three dots) signal sequence to viewers and reduce drop-off between frames. + +###### Poll stories + +- Two options, both plausible — avoid obvious right answers. +- Create a reason to return: "MaƱana revelamos el promedio real" drives next-day traffic. + +- Benchmark: 20-40% response rate on engaged audiences. + +###### Multi-frame sequences + +- Each frame must have a clear progress indicator so viewers know there's more. +- Each frame must have a tap hint (e.g., "Toca para continuar →") except the last. + +- Last frame ends with a CTA, not a tap hint. +- File naming: `story3a.html`,`story3b.html`,`story3c.html` for the 3 frames of Story 3. + +###### Same angle, different execution — never just resize a feed post + +| Feed post | Story adaptation | + +|---|---| + +| Pain point with supporting copy | Strip to the one-liner only — huge on screen, nothing else | + +| Educational post with data | Turn into a poll question — let the audience engage, reveal answer next day | + +| Feature walkthrough | 3-frame sequence: Frame 1 = problem, Frame 2 = solution stat, Frame 3 = result UI | + +| Relationship/split concept | Vertical split (top half / bottom half) unified at the seam | + +| Tips list (3 items) | 3 separate frames, one per tip, "Tip 1 de 3" format | + +### TikTok captions — 4,000 chars (up from 2,200) + +- TikTok is now a search engine — ~40% of Gen Z searches here before Google. Front-load keywords in the caption for TikTok SEO. The caption is indexed; use it for terms your video doesn't say out loud. + +### TikTok Video Production (Composited Short-Form Video) + +The skill CAN produce TikTok-format video (1080Ɨ1920, 9:16) using FFmpeg + AI-generated clips. This is not just captions — it is full video production. + +**API capability disclosure — mandatory before starting:** When producing TikTok video, always inform the user upfront that two quality tiers exist: + +- **Without an external API (default):** AI-generated clips via the built-in media-generation tool — cinematic-style footage, good for most use cases, no extra setup or cost. +- **With an external API (higher quality):** Services like Runway Gen-3, Pika, or Kling can produce significantly more realistic and controllable footage, but require a paid API key from the user. + +Always present both options and ask which they prefer before generating any clips. Never silently call a paid external API. Never assume the user knows these options exist — they usually don't. + +#### Production workflow + +1. Write a scene brief: 3-5 scenes, each with a visual prompt, text overlays, and duration (6-8s per scene is ideal). Total target: 20-30s. +2. Generate AI clips using the media-generation skill — one prompt per scene, 9:16 format. + +3. Prepare brand fonts and assets (logo PNG). +4. Compose with FFmpeg using a Node.js script (`.cjs`). + +5. Output to `client/public/videos/`— served at`/videos/` on the Replit domain. + +##### FFmpeg in Replit NixOS + +- FFmpeg v6+ is available. Locate it: `ls /nix/store/*ffmpeg-full*/bin/ffmpeg 2>/dev/null | head -1` +- Run via `execFileSync('ffmpeg', args)` — do NOT use shell string commands (escaping nightmare). + +###### Font handling — Inter (or any Google Font) + +- Download the GitHub release zip: `https://github.com/rsms/inter/releases/download/v4.0/Inter-4.0.zip` +- Extract TTF files using Node.js `zlib.inflateRawSync()`— do not assume`unzip` or Python are available. + +- Write to `/tmp/tiktok/fonts/Inter-Black.ttf`,`Inter-Bold.ttf`,`Inter-Regular.ttf`. +- Always use the brand font. DejaVu (FFmpeg's fallback) looks wrong on brand content. + +###### FFmpeg filter techniques + +```bash + +# Dark overlay for text readability on top of any clip + +drawbox=x=0:y=0:w=iw:h=ih:color=0x000000@0.50:t=fill + +# Text overlay — use execFileSync (array args), never shell strings, so UTF-8 works directly + +drawtext=fontfile='/path/Inter-Black.ttf':fontsize=110:fontcolor=0xffffff:x=(w-text_w)/2:y=700:text='Tu texto aqui' + +# Logo overlay — scale first, split for N scenes, then overlay each + +[logoInput]scale=185:-1,split=4[logo0][logo1][logo2][logo3] + +[clip_pre][logo0]overlay=x=65:y=72:format=auto[clip_out] + +# Xfade transition between clips (0.4s fade) + +[c0][c1]xfade=transition=fade:duration=0.4:offset=5.6[v01] + +# Audio: music bed, trim to total duration, fade in/out + +[musicInput]atrim=0:24.8,afade=t=in:st=0:d=1.0,afade=t=out:st=23.0:d=1.8[aout] + +``` + +###### Scene structure that works (4-scene formula) + +| Scene | Clip prompt | Text role | Duration | + +|---|---|---|---| + +| Hook | Person reacting to a pain point (wide shot) | Big provocative question, brand color accent | 6s | + +| Pain | Close-up showing the problem (phone, account, etc.) | Short punchy lines, high contrast | 6s | + +| Solution | App/product in use or aspirational moment | Feature bullets, subdued overlay (show the product) | 6s | + +| CTA | Positive resolution, couple/family | Download prompt, URL badge, attribution | 8s | + +###### Overlay composition rules + +- Dark overlay alpha: 0.40–0.55 for clips that need text; 0.35–0.45 for product/app clips (show them). +- Text hierarchy: headline in brand color or white at 110-130px (Inter Black), body at 50-70px (Inter Bold), captions at 36-44px (Inter Regular). + +- Logo: top-left corner, ~185px wide, every scene — use `scale=185:-1,split=N`. +- All content within 140px–1780px vertical (safe zone same as Stories: avoid top 14% and bottom 20%). + +###### Output settings (always use these exactly) + +```text + +-c:v libx264 -preset fast -crf 18 -pix_fmt yuv420p -movflags +faststart -c:a aac -b:a 192k + +``` + +###### Music licensing + +- If using CC BY music (e.g., Kevin MacLeod), attribution must appear IN the video (small text overlay, last scene), not just in the caption. Caption-only attribution does not satisfy CC BY for video. +- Recommended free source: freemusicarchive.org, filter by CC BY. + +###### Canvas embedding + +- Always resolve the domain with `echo $REPLIT_DOMAINS` before setting a canvas video shape URL. Never hardcode a domain — Replit domains change between sessions. +- Video shape URL format: `https:///videos/filename.mp4` + +### Newsletters — Optimize for clicks, not opens + +- **Apple Mail Privacy Protection (MPP) inflates open rates by ~18 percentage points.**Apple Mail is ~46% market share and pre-fetches tracking pixels. A "42% open rate" in 2025 ā‰ˆ a 24% open rate in 2020.**Track click rate (benchmark: ~2%) and CTOR (10-20%) instead.** +- **Subject line:** 30-50 chars. Avoid "Free," ALL CAPS, multiple "!!!" — spam filter triggers. B2B: longer, specific subject lines outperform short clever ones. + +- **Preview/preheader text:** adds ~6pp to open rate when used — but Gmail's Gemini now auto-generates previews, so don't rely on controlling it. Write the first sentence of the body as a second hook. +- One primary CTA. Every additional CTA cuts click rate. + +## Step 3: Hook Formulas (Named Patterns) + +Don't say "write a hook" — pick a pattern: + +| Pattern | Template | Why it works | + +|---|---|---| + +| **Contrarian** | "Everyone says X. Here's why that's wrong." | Cognitive dissonance forces resolution | + +| **Curiosity gap** | "I tried X for 30 days. Day 17 broke me." | Open loop — brain needs closure | + +| **Specificity signal** | "$47,212 in 90 days. Here's the exact stack." | Odd numbers read as true, round numbers read as marketing | + +| **Negative hook** | "3 mistakes that cost me [outcome]" | Loss aversion > gain seeking | + +| **Callout** | "If you're a [role] still doing X, read this." | Self-selection = higher-intent readers | + +| **Slippery slope** | "It started with one Slack message." | Narrative momentum | + +| **Permission** | "Unpopular opinion: [take]" | Pre-frames disagreement as expected | + +**Banned openers:** "I'm excited to share," "Hey everyone," "As a [title]," "In today's fast-paced world." + +## Step 4: Repurposing Waterfall + +One long-form piece → 8+ assets: + +1. **Blog post** (1,500 words) → +2. **X thread** (extract each H2 as a tweet, intro = hook) → + +3. **LinkedIn post** (pick the single most contrarian point, 800 chars) → +4. **LinkedIn carousel** (each H2 = 1 slide; carousels get highest dwell time) → + +5. **Newsletter section** (add personal context + behind-the-scenes) → +6. **Instagram feed post** (hook + 3-5 supporting points, 1080Ɨ1080 or 1080Ɨ1350) → + +7. **Instagram Story** (strip the feed hook to a single line, or turn the educational point into a poll) → +8. **TikTok/Reel script** (the hook + the \#1 takeaway in 30 sec) + +**Key rule for Stories in the waterfall:** same *angle*as the feed post, completely different*execution*. Never just crop or resize a feed post into a Story — re-author it according to the story format table above. + +Build repurposing scripts in Python when batch-processing: parse markdown H2s → split into platform templates → enforce char limits programmatically. + +## Content Frameworks + +- **PAS** (Problem → Agitate → Solve) — best for conversion-focused posts +- **BAB** (Before → After → Bridge) — best for transformation stories + +- **AIDA** (Attention → Interest → Desire → Action) — best for launches +- **SLAP** (Stop → Look → Act → Purchase) — best for short-form (Reels/TikTok captions) + +## Validation + +Before delivering, verify: + +- Char counts against platform limits (count programmatically, don't eyeball) +- Hook fits in the truncation window (110 chars for LinkedIn mobile, 125 for Instagram feed) + +- No banned openers +- One CTA per piece + +- For Stories: all content confirmed inside the 14%–80% safe zone + +## Limitations + +- Cannot post to platforms or access analytics +- Cannot generate static images directly — use the media-generation skill for images; use the ad-creative skill for HTML/CSS visual story designs + +- **CAN produce composited short-form video** (TikTok/Reels) via FFmpeg + AI clip generation — see TikTok Video Production section above +- Paid external video APIs (Runway, Pika, Kling) require user consent and their own API key before use + +- Voice matching quality scales with example count diff --git a/.local/secondary_skills/deep-research/.fingerprint b/.local/secondary_skills/deep-research/.fingerprint new file mode 100644 index 0000000..127c9b2 --- /dev/null +++ b/.local/secondary_skills/deep-research/.fingerprint @@ -0,0 +1 @@ +0395ab728015711c39de54766b25eb6d \ No newline at end of file diff --git a/.local/secondary_skills/deep-research/SKILL.md b/.local/secondary_skills/deep-research/SKILL.md new file mode 100644 index 0000000..cfecd94 --- /dev/null +++ b/.local/secondary_skills/deep-research/SKILL.md @@ -0,0 +1,517 @@ +--- +name: deep-research +description: Conduct thorough, multi-source research with structured reports and source scoring. +--- + +# Deep Research + +Conduct comprehensive, multi-source research on complex topics. Systematically gather, evaluate, triangulate, and synthesize information into structured reports with proper citations and source credibility scoring. + +**Autonomy Principle:** Operate independently. Infer assumptions from context (technical query = technical audience, comparison = balanced perspective, trend = recent 1-2 years). Only stop for critical errors or incomprehensible queries. + +## When to Use + +Activate this skill when the user's request matches any of these patterns: + +### Explicit research requests + +- "Research this," "find out about," "do a deep dive on" +- "Write a research report on..." + +- "White paper on..." / "Briefing on..." +- "Investigate [topic]" + +#### Industry & market analysis + +- "What's the state of [industry/market]?" +- "Survey the landscape of..." + +- "Competitive landscape of [industry]" (no stock tickers involved) +- "Trend analysis on [topic]" + +- "How does [country/region] compare for [business activity]?" + +##### Decision-support research + +- "Due diligence on [private company/market]" (non-public companies) +- "What should I know before [entering a market / making a decision]?" + +- "Pros and cons of [strategy/approach/technology]" +- "What are the risks of [strategy/market/decision]?" + +- "Benchmark [X] against [industry/peers]" (non-financial benchmarking) + +###### Verification & evidence-based analysis + +- "Fact-check this" / "Is [claim] true?" +- "What does the research say about..." + +- Needs to verify claims or compare conflicting information +- Wants to understand a topic from multiple angles with cited sources + +###### Academic & technical evaluation + +- Literature review, technology evaluation, state-of-the-art survey + +## When NOT to Use + +- Simple factual lookups (1-2 searches) --> use web-search directly +- Searching within the user's codebase --> use grep/glob + +- Replit-specific features --> use replit-docs skill +- Specific stock tickers, public company financials, DCF models, portfolio analysis --> use stock-analyzer (it calls deep-research internally for web research) + +- "Analyze this dataset" with user-provided data --> use data-visualization +- "Build a presentation on..." --> use slides skill + +## Decision Tree + +```text + +Request Analysis + ++-- Simple factual lookup (1-2 searches)? --> STOP: Use web-search directly + ++-- Searching user's codebase? --> STOP: Use grep/glob + ++-- Replit-specific feature question? --> STOP: Use replit-docs skill + ++-- Mentions stock tickers or public company --> STOP: Use stock-analyzer + +financials/valuations/DCF? (it calls deep-research internally) + ++-- Wants to analyze a user-provided dataset? --> STOP: Use data-visualization + ++-- Complex multi-angle analysis needed? --> CONTINUE to Depth Selection + +``` + +## Depth Selection + +Select the research depth based on the request complexity. Default to **standard** when unclear. + +| Tier | Subagents | Min Sources | Phases | Estimated Time | When to Use | + +|---|---|---|---|---|---| + +| **Quick** | 3 | 8 | 1, 2, 3, 7 | 2-5 min | Focused question, single domain, time-sensitive | + +| **Standard** | 5 | 15 | 1-7 | 5-15 min | Most research requests, market analysis, technology evaluation | + +| **Deep** | 5 + 2 gap-fill | 25 | 1-8 (all) | 15-30 min | Critical decisions, comprehensive reviews, multi-stakeholder analysis | + +### Selection heuristics + +- User says "quick overview" or "brief research" --> Quick +- User says "research this" or "analyze" --> Standard + +- User says "deep dive," "comprehensive," or "exhaustive" --> Deep +- Country/industry analysis, investment research --> Standard or Deep + +- Technology comparison with 3+ options --> Standard +- Literature review, state-of-the-art survey --> Deep + +## Methodology + +### Phase 1: Scope Definition + +Before starting research, clearly define: + +- **Research question**: What specific question(s) are you answering? +- **Scope boundaries**: What is in/out of scope? + +- **Depth tier**: Quick, Standard, or Deep (see table above) +- **Audience**: Technical, executive, general? (Infer from context if not stated) + +- **Output expectations**: Report format, approximate length + +Then run **1-2 broad landscape searches** to orient yourself and identify the focus areas for decomposition. + +### Phase 2: Planning & Decomposition + +Decompose the topic into distinct, non-overlapping focus areas based on the depth tier: + +- **Quick**: 3 focus areas +- **Standard**: 5 focus areas + +- **Deep**: 5 focus areas (gap-fill subagents added later in Phase 5) + +**How to decompose:** After the broad landscape search, identify angles that together cover the full topic without significant overlap. For example, researching "state of electric vehicles 2026" might decompose into: + +1. **Market & Competition** -- market share, sales figures, manufacturer rankings +2. **Technology** -- battery chemistry, charging standards, range improvements + +3. **Policy & Regulation** -- government incentives, emissions mandates, trade tariffs +4. **Infrastructure** -- charging network growth, grid capacity, urban vs rural + +5. **Consumer & Economics** -- total cost of ownership, resale value, adoption demographics + +### Phase 3: Parallel Source Discovery via Subagents + +Launch all research subagents simultaneously using `startAsyncSubagent`. Each subagent gets a specific focus area, tailored search terms, and a structured output template. + +#### Subagent task template + +```javascript + +await startAsyncSubagent({ + +task: `Research FOCUS AREA: [Area Name] + +Topic context: [1-2 sentence description of the overall research question] + +Your job: Search for information specifically about [focus area]. Run at least 4 webSearch queries with different angles: + +- [specific search term 1] +- [specific search term 2] + +- [specific search term 3] +- [specific search term 4] + +IMPORTANT - Local language searches: If this topic is specific to a non-English-speaking country or region, run at least 1-2 searches in the local language (e.g., Spanish for Latin America, Portuguese for Brazil, French for Francophone Africa). Primary government data, local media, and industry reports are often only available in the local language. + +IMPORTANT - Source freshness: Note the publication date of every source. Flag any source older than 18 months on a fast-moving topic. + +For the most promising results, use webFetch to read the full article. If webFetch returns empty content, try an alternative URL from the search results or run a more specific search query. + +Return your findings using this EXACT structure: + +## Key Facts + +[Bullet list of key data points, each with source URL in parentheses] + +## Notable Claims Requiring Cross-Reference + +[Claims that seem important but only appear in one source, or that conflict with other findings] + +## Source Quality Assessment + +[For each source, rate: Tier 1 (government/multilateral/academic), Tier 2 (major publication/industry report), Tier 3 (blog/opinion/promotional). Note publication date.] + +## Gaps & Unanswered Questions + +[What you could not find or what needs deeper investigation] + +## Sources + +[Numbered list with title, URL, publication date (if available), and tier rating] + +Minimum: 5 distinct sources with URLs` + +}); + +``` + +##### Launch pattern + +```javascript + +// Launch all subagents simultaneously + +await startAsyncSubagent({ task: `Research FOCUS AREA 1: [Area] ...` }); + +await startAsyncSubagent({ task: `Research FOCUS AREA 2: [Area] ...` }); + +await startAsyncSubagent({ task: `Research FOCUS AREA 3: [Area] ...` }); + +// ... (3 for Quick, 5 for Standard/Deep) + +``` + +Then call the `wait_for_background_tasks` tool to collect their results. + +Each subagent should: + +- Run 4+ `webSearch` queries with different phrasings and angles +- Include at least 1-2 local-language searches for country/region-specific topics + +- Use `webFetch` on the 2-3 most relevant results to extract detailed data +- Retry with alternative URLs if webFetch returns empty content + +- Return findings using the structured template above +- Flag any claims that conflict with other results + +- Note publication dates and assess source freshness + +This approach gathers **25+ distinct sources** across focus areas simultaneously, producing far more comprehensive coverage than sequential searching. + +### Phase 4: Triangulation & Source Evaluation + +After collecting all subagent results, systematically evaluate and cross-reference: + +#### Source credibility tiers + +| Tier | Description | Examples | Weight | + +|---|---|---|---| + +| **Tier 1** | Government, multilateral, academic, official statistics | IMF, World Bank, central banks, peer-reviewed journals, SEC filings | Highest -- treat as ground truth unless contradicted by multiple Tier 1 sources | + +| **Tier 2** | Major publications, established industry reports, reputable news | Reuters, Bloomberg, Chambers & Partners, LAVCA, Big 4 reports | High -- reliable but verify key claims | + +| **Tier 3** | Industry blogs, company websites, opinion pieces, promotional content | Company press releases, consultant blogs, sponsored content | Supporting only -- never use as sole source for a claim | + +##### Triangulation rules + +- Every major claim must be supported by **3+ sources** (at least 2 Tier 1 or Tier 2) +- When sources conflict on a data point, prefer: Tier 1 > Tier 2 > Tier 3, and more recent > older + +- When Tier 1 sources conflict with each other, present both figures and note the discrepancy +- Flag any finding that rests on a single source, regardless of tier + +- Note the publication date of key data points; flag anything older than 18 months on fast-moving topics + +###### Conflict resolution for quantitative data + +When multiple sources report different numbers (e.g., GDP figures, market sizes): + +1. Prefer the primary/official source (e.g., central bank over news article) +2. If both are primary sources, present the range and note the methodology difference + +3. Never silently pick one number -- acknowledge the variance + +### Phase 5: Gap Analysis & Follow-Up (Standard and Deep tiers only) + +Review the collected findings for completeness: + +- Identify claims with fewer than 3 supporting sources +- Identify sections with thin coverage or missing data + +- Note unanswered questions flagged by subagents +- Check whether any focus area returned significantly fewer sources than others + +**For Deep tier only:** Launch 1-2 targeted follow-up subagents to fill the most critical gaps: + +```javascript + +await startAsyncSubagent({ + +task: `GAP-FILL RESEARCH: [Specific gap identified] + +Context: During initial research on [topic], we found insufficient data on [gap]. + +Your job: Run 3-4 targeted searches to fill this specific gap: + +- [targeted search term 1] +- [targeted search term 2] + +- [targeted search term 3] + +Return findings using the same structured template as the initial research.` + +}); + +``` + +### Phase 6: Critique & Self-Review (Deep tier only) + +Before writing the final report, conduct a critical self-review: + +- **Weak claims:** Are any findings supported by only Tier 3 sources? Downgrade or remove them. +- **Balance:** Does the report present multiple perspectives, or does it lean toward one viewpoint? + +- **Logical coherence:** Do the findings tell a consistent story? Are there contradictions that need to be addressed? +- **Completeness:** Does the report answer the original research question fully? + +- **Freshness:** Are key data points current, or are they based on outdated sources? +- **Speculation vs. fact:** Is every claim clearly labeled as established fact, expert opinion, or speculation? + +### Phase 7: Report Writing & Synthesis + +Write the report following these principles: + +#### Writing style + +- **Prose-first (80%+ prose).** Write in flowing paragraphs, not bullet-point dumps. Bullets are acceptable for data tables, source lists, and comparison matrices -- but the analysis itself should be narrative. +- Lead with the most important findings + +- Support every factual claim with an inline citation [N] referencing the numbered source list +- Acknowledge limitations and uncertainties explicitly + +- Distinguish clearly between established facts, expert opinions, and speculation +- Provide actionable recommendations where appropriate + +##### Section word count guidance + +| Section | Target Length | + +|---|---| + +| Executive Summary | 200-400 words | + +| Background/Context | 200-500 words | + +| Each Major Finding | 400-1,500 words | + +| Analysis/Synthesis | 500-1,000 words | + +| Limitations | 100-300 words | + +| Recommendations | 200-500 words | + +###### Quality gates (must pass before delivering) + +| Gate | Requirement | + +|---|---| + +| Source count | Quick: 8+, Standard: 15+, Deep: 25+ | + +| Claims per finding | 3+ sources supporting each major claim | + +| Citation coverage | Every factual claim has an inline [N] citation | + +| No placeholders | Zero "TBD," "to be determined," or "[need source]" entries | + +| Source list complete | Every [N] citation maps to a numbered source with URL | + +| Freshness | Key data points are from the last 18 months (flagged if older) | + +| Prose ratio | 80%+ of analysis sections are prose, not bullets | + +## Output Format + +### Research Report Structure + +```text + +# [Research Topic] + +**Research Date:** [Date] + +**Depth:** [Quick / Standard / Deep] + +**Sources Consulted:** [Number] + +## Executive Summary + +[2-3 paragraph overview of key findings and conclusions. 200-400 words.] + +## Background + +[Context needed to understand the topic. 200-500 words.] + +## Key Findings + +### Finding 1: [Theme] + +[Detailed prose analysis with inline source citations [N]. 400-1,500 words.] + +### Finding 2: [Theme] + +[Detailed prose analysis with inline source citations [N]. 400-1,500 words.] + +### Finding 3: [Theme] + +[Detailed prose analysis with inline source citations [N]. 400-1,500 words.] + +[Additional findings as needed -- typically 4-8 for Standard/Deep] + +## Analysis + +[Cross-cutting analysis, patterns, implications. Draw connections between + +findings that reveal insights not visible in any single section. 500-1,000 words.] + +## Limitations + +[What couldn't be determined, data gaps, source constraints, caveats. 100-300 words.] + +## Recommendations + +[Actionable next steps based on findings. 200-500 words.] + +## Sources + +[Numbered list of all sources with: title, URL, publication date, tier rating] + +1. [Title] -- [URL] (Published: [date], Tier [1/2/3]) +2. ... + +``` + +## Example Workflow + +```javascript + +// Phase 1: Scope -- broad landscape search + +const overview = await webSearch({ query: "state of electric vehicle market 2026" }); + +// Determine depth tier (Standard for this example) + +// Identify 5 focus areas from overview results + +// Phase 3: Launch 5 parallel research subagents + +await startAsyncSubagent({ + +task: `Research FOCUS AREA 1: EV Market & Competition + +Topic context: Comprehensive analysis of the global electric vehicle industry in 2026. + +Your job: Search for information specifically about EV market share, sales figures, and manufacturer rankings. Run at least 4 webSearch queries: + +- "EV market share by manufacturer 2025 2026" +- "electric vehicle sales global rankings" + +- "Tesla BYD market share comparison 2026" +- "electric vehicle market size revenue 2026" + +For country-specific angles, also search in relevant local languages. + +If webFetch returns empty content, try alternative URLs. + +Return findings using the structured template with Key Facts, Notable Claims, Source Quality Assessment, Gaps, and Sources.` + +}); + +await startAsyncSubagent({ task: `Research FOCUS AREA 2: EV Battery Technology ...` }); + +await startAsyncSubagent({ task: `Research FOCUS AREA 3: EV Policy & Regulation ...` }); + +await startAsyncSubagent({ task: `Research FOCUS AREA 4: EV Charging Infrastructure ...` }); + +await startAsyncSubagent({ task: `Research FOCUS AREA 5: EV Consumer Economics ...` }); + +// Phase 4: Triangulate -- evaluate sources, resolve conflicts, score credibility + +// Phase 5: Gap analysis -- identify weak spots, launch follow-up if Deep tier + +// Phase 6: Critique -- self-review for Deep tier + +// Phase 7: Write the report following quality gates and prose-first style + +// Save to research/[topic].md and present to user + +``` + +After the launch block above, call the `wait_for_background_tasks` tool to wait for subagents, then proceed to Phase 4. + +## Best Practices + +1. **Cast a wide net first, then narrow** -- start with broad searches before diving into specifics +2. **Cross-reference critical claims** -- never rely on a single source for important facts; require 3+ sources for major claims + +3. **Cite everything inline** -- every factual claim should have a [N] citation immediately following it +4. **Note disagreements** -- when sources conflict, present both sides and analyze why + +5. **Timestamp your research** -- note when the research was conducted, as information changes +6. **Separate facts from analysis** -- clearly distinguish between what sources say and your interpretation + +7. **Search in local languages** -- for country/region-specific research, primary sources are often only in the local language +8. **Handle fetch failures gracefully** -- if webFetch returns empty content, try alternative URLs or run more targeted search queries + +9. **Prefer authoritative sources** -- when numbers conflict, prefer Tier 1 (government/multilateral) over Tier 2 (publications) over Tier 3 (blogs/promotional) +10. **Flag stale data** -- note when key data points are older than 18 months on fast-moving topics + +## Limitations + +- Cannot access paywalled academic journals or subscription databases +- Cannot access social media content (LinkedIn, Twitter, Reddit) + +- Web sources may have varying levels of reliability +- Research is a snapshot in time -- findings may change + +- Cannot conduct primary research (surveys, interviews, experiments) +- webFetch may fail on some pages (JavaScript-heavy sites, paywalled content); mitigate with retry and alternative URLs diff --git a/.local/secondary_skills/design-thinker/.fingerprint b/.local/secondary_skills/design-thinker/.fingerprint new file mode 100644 index 0000000..6f32488 --- /dev/null +++ b/.local/secondary_skills/design-thinker/.fingerprint @@ -0,0 +1 @@ +dbafacda768438645df38d51631e54f8 \ No newline at end of file diff --git a/.local/secondary_skills/design-thinker/SKILL.md b/.local/secondary_skills/design-thinker/SKILL.md new file mode 100644 index 0000000..d623bd9 --- /dev/null +++ b/.local/secondary_skills/design-thinker/SKILL.md @@ -0,0 +1,327 @@ +--- +name: design-thinker +description: Apply design thinking to validate ideas, define audiences, and prioritize directions. +--- + +# Design Thinking + +Apply human-centered problem solving. Three frameworks dominate industry practice — pick based on what the user actually needs, don't default to IDEO's 5 phases. + +## When to Use + +- Ambiguous problem space, no obvious solution +- "Why aren't users adopting X?" / "What should we build next?" + +- Stuck and needs structured divergence +- "Who is this for?" / "Who should we target?" — audience definition and user persona synthesis + +- "Is this idea worth pursuing?" / "Should we invest in X?" — idea validation before committing resources +- "We have too many ideas, which one?" / "Help me prioritize" — structured narrowing from many directions to one + +- "What problem are we actually solving?" — problem reframing when the real issue might be upstream +- "Why did this product/feature fail?" — post-mortem through a design thinking lens (wrong problem, wrong audience, or wrong solution) + +## When NOT to Use + +- Known problem, known solution, just needs execution (skip straight to PRD — use product-manager skill) +- Visual/UI implementation (use design skill) + +- Technical debugging +- Pure information gathering with no decision needed (use deep-research skill) + +- Competitive positioning or feature comparison (use competitive-analysis skill) + +## Depth Calibration + +Not every problem needs a full board. Before starting, gauge the scope and pick the right depth: + +### Quick Mode (10-15 min, 2-3 cards per phase) + +Use when: the user has a specific question like "should I build X or Y?", the domain is narrow, or they just want a structured opinion. Research is 1-2 searches. Canvas output is compact — skip sidebar annotations, limit to 2 concepts, use a single assumption card. No forces diagram. + +### Standard Mode (30-45 min, full board) + +Use when: the problem space is moderately open — "what should we build for market X?" or "why is feature Y underperforming?". Research is 3-5 searches across different angles. Full canvas board with all sections. Forces diagram for top concept only. + +### Deep Mode (60+ min, full board + extended research) + +Use when: high-stakes strategic decisions, entering new markets, or pivoting a product. Research is exhaustive — 5+ searches, reading full articles via webFetch, cross-referencing data. Full canvas board with forces diagrams for every concept, detailed assumption mapping, and confidence scoring. Consider launching parallel research subagents for different angles. + +Default to Standard Mode. Upgrade to Deep if the user's question involves a new market, significant investment, or a pivot. Downgrade to Quick if the question is binary or narrowly scoped. + +## Three Frameworks — Choose Wisely + +### 1. Double Diamond (UK Design Council, 2004) — for ambiguous problems + +Two diamonds = two diverge-then-converge cycles. **Discover**(go wide on problem research) →**Define**(narrow to problem statement) →**Develop**(go wide on solutions) →**Deliver** (narrow to one, ship it). + +Critical insight: most teams skip the first diamond and jump straight to solution brainstorming. The first diamond exists to prevent solving the wrong problem beautifully. + +**Use when**: problem isn't yet defined, timeline is weeks not days. + +### 2. GV Design Sprint (Jake Knapp, Google Ventures, 2010) — for validation speed + +5 days, 5 phases, hard time-box. Map (Mon) → Sketch (Tue) → Decide (Wed) → Prototype (Thu) → Test with 5 real users (Fri). Full method free at `gv.com/sprint`and`designsprintkit.withgoogle.com`. + +**Known weakness**: users appear on Day 5, not Day 1. The sprint relies on team intuition to frame the problem — you can spend 5 days sprinting toward the wrong target. Fix: run JTBD interviews *before* the sprint to pick the problem. + +**Use when**: problem is defined, team can commit 5 uninterrupted days, you need a go/no-go decision fast. + +**"5 users" is not arbitrary**: Nielsen Norman Group research shows 5 users find ~85% of usability problems. Diminishing returns after that. + +### 3. JTBD Switch Interview (Bob Moesta / Re-Wired Group) — for understanding why people buy + +Not a workshop — a forensic interview technique. Interview people who *recently switched* (bought your product, or churned to a competitor). 45-60 minutes. Reconstruct their timeline, don't ask about features. + +**The Timeline** (walk backward through their actual purchase): + +1. **First thought** — when did it first occur to you this was a problem? +2. **Passive looking** — noticing solutions but not acting + +3. **Event one** — something happens that makes it urgent +4. **Active looking** — comparing options, raised hand + +5. **Deciding** — what tipped it? +6. **Buying** — the actual moment + +**The Four Forces** (what made the switch happen): + +| Force | Direction | Probe | + +|---|---|---| + +| Push of the situation | Toward switch | "What was happening that made the old way stop working?" | + +| Pull of the new solution | Toward switch | "When you imagined having this, what got you excited?" | + +| Anxiety of the new | Against switch | "What worried you about switching?" | + +| Habit of the present | Against switch | "What was good enough about what you had?" | + +Switch only happens when Push + Pull > Anxiety + Habit. If someone didn't buy, one of the blocking forces won. + +**Key technique**: ask about the *situation*, never the feature. Not "do you like the dashboard?" but "walk me through the last time you opened it — what were you in the middle of?" Reference: the "Mattress Interview" at `jobstobedone.org` — Moesta interviews a guy about buying a mattress for 45 min and uncovers it was actually about his marriage. + +**Use when**: you have customers but don't understand why they chose you, or you're losing deals and don't know why. + +## Research Synthesis + +Research is only useful if it feeds directly into the framework phases. Follow this process to avoid the common failure of doing research and then ignoring it during ideation. + +### Step 1: Gather (DISCOVER phase) + +Run 3-5 web searches across different angles of the problem space. For each search, extract: + +- **Hard numbers** — market size, penetration rates, growth figures, demographic data +- **Pain signals** — what people complain about, what's broken, what's missing + +- **Existing solutions** — who's already solving parts of this, and where are they falling short + +### Step 2: Distill (DEFINE phase) + +From the raw research, identify 2-3 **key insights** — non-obvious patterns that connect multiple data points. Each insight must be grounded in evidence from Step 1, not invented. Format each as: + +> **Insight**: [pattern observed] +> +> **Evidence**: [specific data points or sources that support it] +> +> **Implication**: [what this means for what we should build] + +These insights directly feed the HMW statement. The HMW should address the most important insight, not the most obvious problem. + +### Step 3: Ground (DEVELOP phase) + +Every solution concept must reference at least one insight from Step 2 and one data point from Step 1. This prevents "idea theater" — generating concepts that sound creative but ignore the research. If a concept can't be traced back to the research, cut it. + +### Step 4: Stress-test (DELIVER phase) + +For the recommended concept, revisit the research to identify what could invalidate it. Look for counter-evidence, missing data, or assumptions the research didn't cover. These become the riskiest assumptions to test. + +## Core Tools (Framework-Agnostic) + +**How Might We (HMW)** — reframe problem as opportunity. Scope test: too narrow bakes in the solution ("HMW add a share button"), too broad is unactionable ("HMW make users happy"). Right: "HMW help busy parents find 20-minute recipes without meal-planning guilt?" + +**Crazy 8s** (from GV Sprint) — fold paper into 8 panels, sketch 8 distinct ideas in 8 minutes. Forces past the obvious first 3 ideas. Works solo or in groups. + +**Assumption Mapping** — plot assumptions on Importance Ɨ Evidence 2Ɨ2. High-importance + low-evidence = test first. This picks your prototype target. + +**Empathy Map** (Dave Gray, XPLANE) — Say / Think / Do / Feel quadrants around a user. "Think" and "Feel" are where insight lives — they're the gap between what users say and what they do. + +**5-Act Interview** (GV test-day script): Friendly welcome → context questions → intro the prototype → tasks (watch, don't help) → debrief. One person interviews, team watches on video in another room and takes notes. + +**Adoption Forces (applied to every concept)** — The JTBD Four Forces framework is too useful to reserve only for JTBD analyses. For every solution concept in DEVELOP, map these four forces from the *target user's perspective*: + +| Force | Direction | Question to answer | + +|---|---|---| + +| Push | Toward adoption | What's painful enough about the status quo to make them try something new? | + +| Pull | Toward adoption | What's exciting about this concept — what do they imagine getting? | + +| Anxiety | Against adoption | What scares them about switching — cost, learning curve, risk, trust? | + +| Habit | Against adoption | What's good enough about their current way — why haven't they already changed? | + +Adoption happens when Push + Pull > Anxiety + Habit. If the forces don't balance toward adoption, the concept needs redesign — either amplify Push/Pull or reduce Anxiety/Habit. In Standard mode, do this for the top recommended concept. In Deep mode, do it for every concept. + +## Output Format + +```markdown + +# [Challenge] + +## Framework Used + +[Double Diamond / GV Sprint / JTBD — and why this one] + +## Problem Definition + +### HMW Statement + +### Key Insights (with evidence — quote or observation, not assumption) + +## [If JTBD] Forces Diagram + +| Push | Pull | Anxiety | Habit | + +|---|---|---|---| + +## Solution Concepts + +| Concept | Desirable? | Feasible? | Viable? | Riskiest assumption | + +|---|---|---|---|---| + +## Adoption Forces (for recommended concept, or all concepts in Deep mode) + +| Force | Assessment | + +|---|---| + +| Push (pain of status quo) | | + +| Pull (appeal of new solution) | | + +| Anxiety (fears about switching) | | + +| Habit (comfort of current way) | | + +| **Balance** | Push + Pull [>/<] Anxiety + Habit | + +## Recommendation + +### Conviction Level + +[Low / Medium / High] — State your confidence and what would change it. + +- **Current conviction**: [e.g., "Medium — the pain signal is strong but adoption behavior is unproven"] +- **Would increase to High if**: [e.g., "3/5 merchants in a pilot use the app daily for 2 weeks"] + +- **Would decrease if**: [e.g., "merchants report they tried similar apps before and abandoned them"] + +## Prototype Plan + +- What to build (lowest fidelity that tests the assumption) +- Who to test with (5 users, recruited how) + +- What "success" looks like + +## Next Steps + +``` + +## Canvas Presentation + +When presenting design thinking analysis on the canvas, follow these rules for a clear, skimmable board. + +### Shape Types & When to Use Each + +| Shape | Use For | Why | + +|---|---|---| + +| `note` (sticky note) | Section headers, sidebar annotations, key stats | Fixed 200px width. Auto-sizes font based on text length — fewer words = bigger text. Perfect for bold single-word headers. | + +| `geo`(rectangle) | Content cards, full-width banners, problem statements | Respects`w`and`h`— use for wide content (500px+ cards, 1600px+ banners). Set`fill: "solid"` and pick a color. | + +| `geo`(arrow-down / arrow-right) | Flow indicators between sections | Shows the progression through the framework. Use`fill: "solid"`. | + +| `text` | Small inline labels like "vs" between forces | Auto-sizes, minimal visual weight. | + +### Layout Rules + +1. **Headers as sticky notes with minimal text** — Use 1-2 words max (e.g., "DISCOVER", "DEFINE", "FORCES"). The note shape auto-scales font size inversely to text length, so short text = large, skimmable headers. +2. **Content cards as geo rectangles** — 500px wide for 3-column layouts, 780px for 2-column layouts, 1600px+ for full-width banners. Always set `fill: "solid"` and a color. + +3. **Left-column header notes, right-side content** — Place header sticky notes at x=1400, content cards starting at x=1670 (leaving a 70px gap after the 200px-wide header note). +4. **Vertical spacing** — 80-100px between rows within a section, 120-150px between sections. This keeps the board breathable and skimmable. + +5. **Arrow shapes between sections** — Place `geo`shapes with`arrow-down` geo centered horizontally between sections to show flow. Use the section's color. +6. **Annotation stickies as sidebar** — Place `note` shapes at x=3350 (far right) aligned vertically with their related section. Use for market stats, key quotes, risk callouts — short punchy content that adds context without cluttering the main flow. + +7. **Color coding by section** — Be consistent: + +- Violet: title, concepts +- Blue: discover + +- Green: define +- Orange: develop / forces + +- Red: deliver +- Yellow: key callouts (problem statement, switch rule, recommendation) + +- Light-* variants for content cards within each section + +1. **JTBD Forces layout** — Use 2x2 grid: Push (top-left, light-red) vs Pull (top-right, light-green), Anxiety (bottom-left, orange) vs Habit (bottom-right, grey). Place arrow-right shapes and "vs" text labels between the pairs. + +### Canvas Gotchas + +- **Sticky notes (`note`type) are always 200px wide** — the`w` parameter is ignored. Plan layouts around this constraint. +- **`labelColor: "white"` can cause rendering errors** — avoid it. Use lighter fill colors where default black text is readable. + +- **`color: "black"`on geo shapes with`fill: "solid"`causes errors** — use`grey` or a dark supported color instead. +- **Always call `get_canvas_state` before placing shapes** — check for existing content and find empty space. + +- **Delete before recreate** — when updating shapes, delete first then create fresh. Updates to notes can behave unexpectedly. + +### Example: Placing a Section + +```text + +1. Header note (big text): + +{ type: "note", x: 1400, y: Y, w: 200, h: 200, color: "blue", text: "DISCOVER" } + +2. Content cards (3-column): + +{ type: "geo", geo: "rectangle", x: 1670, y: Y, w: 500, h: 260, color: "light-blue", fill: "solid", text: "..." } + +{ type: "geo", geo: "rectangle", x: 2220, y: Y, w: 500, h: 260, color: "light-violet", fill: "solid", text: "..." } + +{ type: "geo", geo: "rectangle", x: 2770, y: Y, w: 500, h: 260, color: "light-green", fill: "solid", text: "..." } + +3. Flow arrow to next section: + +{ type: "geo", geo: "arrow-down", x: 2300, y: Y+300, w: 80, h: 60, color: "blue", fill: "solid" } + +4. Sidebar annotation: + +{ type: "note", x: 3350, y: Y, w: 200, h: 200, color: "yellow", text: "$45.5B\nmarket by 2028" } + +``` + +## Research + +- `webSearch("[user's problem domain] user research")` for prior art +- `webFetch("https://www.gv.com/sprint/")` for full sprint method + +- `webSearch("[product category] reviews site:reddit.com")` — unfiltered user language for push/anxiety forces +- IDEO Design Kit free methods: `designkit.org/methods` + +## Hard Truths + +- Agent cannot run real interviews — can write the discussion guide, analyze transcripts the user pastes in, and build the synthesis +- Personas without research are fiction. Push user for real data (support tickets, reviews, churn interviews) before building empathy maps + +- Most "design thinking" fails because teams do ideation theater and skip the uncomfortable research. Bias toward the first diamond diff --git a/.local/secondary_skills/excel-generator/.fingerprint b/.local/secondary_skills/excel-generator/.fingerprint new file mode 100644 index 0000000..796c5d8 --- /dev/null +++ b/.local/secondary_skills/excel-generator/.fingerprint @@ -0,0 +1 @@ +7bdf123ed8b3f72765ee52351adbf2b8 \ No newline at end of file diff --git a/.local/secondary_skills/excel-generator/SKILL.md b/.local/secondary_skills/excel-generator/SKILL.md new file mode 100644 index 0000000..3b73475 --- /dev/null +++ b/.local/secondary_skills/excel-generator/SKILL.md @@ -0,0 +1,954 @@ +--- +name: excel-generator +description: Create Excel spreadsheets with formulas, charts, pivot summaries, and financial models. +--- + +# Excel & Spreadsheet Generator + +Create .xlsx files, Google Sheets, and PDF exports with formulas, formatting, charts, data validation, pivot summaries, and financial models. + +Library Selection + +Need Use Install + +Create new .xlsx from scratch, fast, large files xlsxwriter pip install xlsxwriter + +Read/modify existing .xlsx, or round-trip edits openpyxl pip install openpyxl + +Read legacy .xls (Excel 97-2003) xlrd pip install xlrd + +Dump a DataFrame quickly df.to_excel() uses openpyxl/xlsxwriter as engine + +Generate Google Sheets gspread + google-auth pip install gspread google-auth + +Export to PDF LibreOffice CLI system dependency (see PDF section) + +Key gotchas: + +Neither openpyxl nor xlsxwriter can read .xls — only .xlsx. Use xlrd for .xls. + +xlsxwriter is write-only — it cannot open an existing file. Use openpyxl to edit. + +openpyxl uses ~50x the file size in RAM. For 100K+ rows, use xlsxwriter or openpyxl.Workbook(write_only=True). + +Formulas are stored as strings — Python does not evaluate them. Excel computes on open. openpyxl reading a formula cell gives you =SUM(A1:A10), not the result (unless you use data_only=True, which reads the last cached value). + +Core Recipe — openpyxl + +from openpyxl import Workbook + +from openpyxl.styles import Font, PatternFill, Alignment, Border, Side + +from openpyxl.utils import get*column*letter + +from openpyxl.worksheet.table import Table, TableStyleInfo + +from openpyxl.formatting.rule import ColorScaleRule, DataBarRule + +from openpyxl.worksheet.datavalidation import DataValidation + +wb = Workbook() + +ws = wb.active + +ws.title = "Sales" + +headers = ["Product", "Units", "Price", "Revenue"] + +ws.append(headers) + +rows = [("Widget", 120, 9.99), ("Gadget", 80, 14.50), ("Gizmo", 200, 4.25)] + +for r in rows: + +ws.append(r) + +for row in range(2, len(rows) + 2): + +ws[f"D{row}"] = f"=B{row}*C{row}" + +ws[f"D{len(rows)+2}"] = f"=SUM(D2:D{len(rows)+1})" + +header*fill = PatternFill(start*color="2F5496", fill_type="solid") + +for cell in ws[1]: + +cell.font = Font(bold=True, color="FFFFFF") + +cell.fill = header_fill + +cell.alignment = Alignment(horizontal="center") + +cell.border = Border(bottom=Side(border_style="medium")) + +for row in ws.iter*rows(min*row=2, min*col=3, max*col=4): + +for cell in row: + +cell.number_format = '"$"#,##0.00' + +for col in ws.columns: + +max_len = max(len(str(c.value or "")) for c in col) + +ws.column*dimensions[get*column*letter(col[0].column)].width = max*len + 3 + +ws.freeze_panes = "A2" + +tab = Table(displayName="SalesTable", ref=f"A1:D{len(rows)+1}") + +tab.tableStyleInfo = TableStyleInfo(name="TableStyleMedium9", showRowStripes=True) + +ws.add_table(tab) + +ws.conditional_formatting.add(f"D2:D{len(rows)+1}", + +DataBarRule(start*type="min", end*type="max", color="638EC6")) + +dv = DataValidation(type="list", formula1='"Active,Paused,Archived"', allow_blank=True) + +ws.add*data*validation(dv) + +dv.add("E2:E100") + +wb.save("output.xlsx") + +Charts (openpyxl) + +from openpyxl.chart import BarChart, LineChart, PieChart, Reference + +chart = BarChart() + +chart.title = "Revenue by Product" + +chart.y_axis.title = "Revenue ($)" + +data = Reference(ws, min*col=4, min*row=1, max_row=4) + +cats = Reference(ws, min*col=1, min*row=2, max_row=4) + +chart.add*data(data, titles*from_data=True) + +chart.set_categories(cats) + +ws.add_chart(chart, "F2") + +Chart gotchas: + +Reference uses 1-indexed rows/cols (not 0-indexed). + +titles*from*data=True consumes the first row of the data range as the series label — include the header row in data but NOT in cats. + +Supported: BarChart, LineChart, PieChart, ScatterChart, AreaChart, DoughnutChart, RadarChart. 3D variants exist but render inconsistently. + +Charts reference cells — if you later insert rows above, the chart range does NOT auto-adjust. + +xlsxwriter (faster, write-only, richer formatting) + +import xlsxwriter + +wb = xlsxwriter.Workbook("report.xlsx") + +ws = wb.add_worksheet("Data") + +header*fmt = wb.add*format({"bold": True, "bg*color": "#2F5496", "font*color": "white", "border": 1}) + +money*fmt = wb.add*format({"num_format": "$#,##0.00"}) + +ws.write*row(0, 0, ["Product", "Units", "Price", "Revenue"], header*fmt) + +data = [("Widget", 120, 9.99), ("Gadget", 80, 14.50)] + +for i, (p, u, pr) in enumerate(data, start=1): + +ws.write(i, 0, p) + +ws.write(i, 1, u) + +ws.write(i, 2, pr, money_fmt) + +ws.write*formula(i, 3, f"=B{i+1}*C{i+1}", money*fmt) + +ws.autofit() + +ws.freeze_panes(1, 0) + +wb.close() + +pandas Shortcut (multi-sheet with formatting) + +import pandas as pd + +with pd.ExcelWriter("out.xlsx", engine="xlsxwriter") as writer: + +df.to*excel(writer, sheet*name="Data", index=False) + +summary.to*excel(writer, sheet*name="Summary", index=False) + +wb, ws = writer.book, writer.sheets["Data"] + +ws.set_column("A:A", 20) + +ws.autofilter(0, 0, len(df), len(df.columns) - 1) + +Google Sheets Generation + +Use the gspread library with a service account or OAuth credentials. Requires the Google Sheets API and Google Drive API enabled. + +Setup: Check if a Google Sheets integration is available via Replit integrations first. If not, the user needs to provide a service account JSON key. + +import gspread + +from google.oauth2.service_account import Credentials + +scopes = [ + +"", + +"", + +] + +creds = Credentials.from*service*account*file("service*account.json", scopes=scopes) + +gc = gspread.authorize(creds) + +sh = gc.create("Sales Report Q1") + +ws = sh.sheet1 + +ws.update_title("Revenue") + +ws.update("A1:D1", [["Product", "Units", "Price", "Revenue"]]) + +data = [["Widget", 120, 9.99], ["Gadget", 80, 14.50], ["Gizmo", 200, 4.25]] + +ws.update(f"A2:C{len(data)+1}", data) + +for i in range(2, len(data) + 2): + +ws.update_acell(f"D{i}", f"=B{i}*C{i}") + +ws.format("A1:D1", { + +"backgroundColor": {"red": 0.18, "green": 0.33, "blue": 0.59}, + +"textFormat": {"bold": True, "foregroundColor": {"red": 1, "green": 1, "blue": 1}}, + +"horizontalAlignment": "CENTER" + +}) + +ws.format(f"C2:D{len(data)+1}", {"numberFormat": {"type": "CURRENCY", "pattern": "$#,##0.00"}}) + +ws.freeze(rows=1) + +sh.share("", perm_type="user", role="writer") + +print(f"Spreadsheet URL: {sh.url}") + +Batch updates (faster for large writes): + +ws.batch_update([ + +{"range": "A1:D1", "values": [headers]}, + +{"range": f"A2:C{len(data)+1}", "values": data}, + +]) + +Google Sheets gotchas: + +API rate limits: 60 requests/min per user, 300 requests/min per project. Batch writes to stay under. + +update() overwrites — it does not append. Use append_rows() to add to the end. + +Formulas work the same as Excel (US-English function names). + +Charts must be created via the Sheets API v4 batchUpdate with addChart request — gspread does not have a chart helper. + +Conditional formatting requires gspread.utils or raw API calls. + +Alternative — upload .xlsx to Google Drive: + +from googleapiclient.discovery import build + +from googleapiclient.http import MediaFileUpload + +drive = build("drive", "v3", credentials=creds) + +file_metadata = {"name": "Report", "mimeType": "application/vnd.google-apps.spreadsheet"} + +media = MediaFileUpload("report.xlsx", + +mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + +file = drive.files().create(body=file*metadata, media*body=media, + +fields="id,webViewLink").execute() + +print(f"Google Sheets URL: {file['webViewLink']}") + +PDF Export & Print Layout + +Method 1: LibreOffice CLI (best fidelity) + +libreoffice --headless --calc --convert-to pdf --outdir ./output report.xlsx + +import subprocess + +def xlsx*to*pdf(input*path, output*dir="./output"): + +result = subprocess.run( + +["libreoffice", "--headless", "--calc", "--convert-to", "pdf", + +"--outdir", output*dir, input*path], + +capture_output=True, text=True, timeout=60 + +) + +if result.returncode != 0: + +raise RuntimeError(f"Conversion failed: {result.stderr}") + +return f"{output*dir}/{input*path.rsplit['/', 1](-1).replace('.xlsx', '.pdf')}" + +Method 2: Print Layout in openpyxl + +from openpyxl.worksheet.page import PageMargins, PrintPageSetup + +ws.page_setup.orientation = "landscape" + +ws.page*setup.paperSize = ws.PAPERSIZE*LETTER + +ws.page_setup.fitToWidth = 1 + +ws.page_setup.fitToHeight = 0 + +ws.sheet_properties.pageSetUpPr.fitToPage = True + +ws.page_margins = PageMargins(left=0.5, right=0.5, top=0.75, bottom=0.75, + +header=0.3, footer=0.3) + +ws.oddHeader.center.text = "Sales Report — Q1 2026" + +ws.oddHeader.center.font = "Arial,Bold" + +ws.oddHeader.center.size = 12 + +ws.oddFooter.center.text = "Page &P of &N" + +ws.oddFooter.right.text = "&D" + +ws.print*title*rows = "1:1" + +ws.print*area = f"A1:F{last*row}" + +ws.row_breaks.append(openpyxl.worksheet.pagebreak.Break(id=25)) + +Method 3: Print Layout in xlsxwriter + +ws.set_landscape() + +ws.set_paper(1) + +ws.fit*to*pages(1, 0) + +ws.set_margins(left=0.5, right=0.5, top=0.75, bottom=0.75) + +ws.set_header("&C&\\Arial,Bold\\&14 Sales Report") + +ws.set_footer("&CPage &P of &N") + +ws.repeat_rows(0) + +ws.print*area(0, 0, last*row, 5) + +ws.set*page*break(25, 0) + +Print layout tips: + +Always set fitToWidth=1 for wide tables — prevents columns from being cut off across pages. + +Use repeat_rows to repeat headers on every page — critical for multi-page tables. + +Set margins to 0.5" for data-heavy sheets, 0.75"+ for presentation sheets. + +Test with landscape for tables wider than 6 columns. + +For Excel-native PDF: the user can also do File > Export > PDF in Excel after opening. + +Financial Model Recipes + +See `financial-models.md` for complete recipes covering: + +3-Statement Model — Income Statement, Balance Sheet, Cash Flow linked together + +DCF (Discounted Cash Flow) — FCF projections, discount factors, terminal value, equity bridge + +LBO (Leveraged Buyout) — Sources & Uses, debt schedule, cash sweep, MOIC/IRR + +Comparable Company Analysis — Comp table with multiples, summary stats, implied valuation + +Merger Model (M&A) — Accretion/dilution analysis, pro forma EPS + +Common patterns across all financial models: + +Yellow-highlighted cells (#FFF2CC) = user inputs; everything else is formulas + +Use freeze_panes on row 1 (headers) and column A (labels) + +Currency format: '"$"#,##0.0' for millions, '"$"#,##0.00' for precise + +Multiple format: '0.0x' for EV/EBITDA, leverage ratios + +Totals use double-bottom border ("bottom": 6 in xlsxwriter) + +Use named ranges or cell references to the Assumptions sheet for all inputs — never hardcode values in formula sheets + +Always add a section_fmt for visual grouping (bold, light blue background, top+bottom border) + +Pivot-Table-Style Summaries + +Python cannot create native Excel PivotTables programmatically (they require cached data). Instead, build the equivalent summary using formulas or pandas aggregation. + +Pattern 1: pandas groupby to formatted Excel output + +import pandas as pd + +df = pd.DataFrame({ + +"Region": ["East", "East", "West", "West", "East", "West"], + +"Product": ["Widget", "Gadget", "Widget", "Gadget", "Widget", "Gadget"], + +"Revenue": [120, 80, 150, 90, 200, 110], + +"Units": [10, 5, 12, 6, 15, 8], + +}) + +pivot = df.pivot_table( + +values=["Revenue", "Units"], + +index="Region", + +columns="Product", + +aggfunc="sum", + +margins=True, + +margins_name="Total" + +) + +pivot.columns = [f"{val} - {prod}" for val, prod in pivot.columns] + +pivot = pivot.reset_index() + +with pd.ExcelWriter("pivot_report.xlsx", engine="xlsxwriter") as writer: + +df.to*excel(writer, sheet*name="Data", index=False) + +pivot.to*excel(writer, sheet*name="Summary", index=False) + +ws = writer.sheets["Summary"] + +ws.autofit() + +hdr*fmt = writer.book.add*format( + +{"bold": True, "bg*color": "#2F5496", "font*color": "white"}) + +for col_num, value in enumerate(pivot.columns): + +ws.write(0, col*num, value, hdr*fmt) + +Pattern 2: SUMIFS-based pivot using formulas (dynamic in Excel) + +import xlsxwriter + +wb = xlsxwriter.Workbook("formula_pivot.xlsx") + +ws*data = wb.add*worksheet("Data") + +ws*pivot = wb.add*worksheet("Pivot") + +headers = ["Region", "Product", "Revenue"] + +data_rows = [("East", "Widget", 120), ("East", "Gadget", 80), + +("West", "Widget", 150), ("West", "Gadget", 90), + +("East", "Widget", 200), ("West", "Gadget", 110)] + +ws*data.write*row(0, 0, headers) + +for i, row in enumerate(data_rows, 1): + +ws*data.write*row(i, 0, row) + +last*data = len(data*rows) + +regions = ["East", "West"] + +products = ["Widget", "Gadget"] + +ws_pivot.write(0, 0, "Region \\ Product") + +for j, prod in enumerate(products): + +ws_pivot.write(0, j + 1, prod) + +ws_pivot.write(0, len(products) + 1, "Total") + +for i, region in enumerate(regions): + +ws_pivot.write(i + 1, 0, region) + +for j, prod in enumerate(products): + +ws*pivot.write*formula(i + 1, j + 1, + +f'=SUMIFS(Data!C2:C{last*data+1}, Data!A2:A{last*data+1}, ' + +f'A{i+2}, Data!B2:B{last_data+1}, {chr(66+j)}1)') + +ws*pivot.write*formula(i + 1, len(products) + 1, + +f"=SUM(B{i+2}:{chr(65+len(products))}{i+2})") + +ws_pivot.write(len(regions) + 1, 0, "Total") + +for j in range(len(products) + 1): + +col_letter = chr(66 + j) + +ws*pivot.write*formula(len(regions) + 1, j + 1, + +f"=SUM({col*letter}2:{col*letter}{len(regions)+1})") + +wb.close() + +Pattern 3: Multi-dimension pivot with percentage columns + +## After building a pivot, add percentage-of-total columns + +## =Cell / ColumnTotal formatted as "0.0%" + +## =Cell / RowTotal formatted as "0.0%" + +## Use IFERROR to handle division by zero + +Multi-Workbook Linking + +Excel supports cross-workbook references using [filename.xlsx]SheetName!Cell syntax. Python can write these formulas as strings. + +Writing cross-workbook references + +import xlsxwriter + +wb = xlsxwriter.Workbook("master_report.xlsx") + +ws = wb.add_worksheet("Consolidated") + +ws.write(0, 0, "Region") + +ws.write(0, 1, "Revenue") + +ws.write(0, 2, "EBITDA") + +regions = [ + +("East", "east_data.xlsx"), + +("West", "west_data.xlsx"), + +("Central", "central_data.xlsx"), + +] + +for i, (region, filename) in enumerate(regions, 1): + +ws.write(i, 0, region) + +ws.write_formula(i, 1, f"='[{filename}]Summary'!B2") + +ws.write_formula(i, 2, f"='[{filename}]Summary'!B5") + +ws.write(len(regions) + 1, 0, "Total") + +ws.write_formula(len(regions) + 1, 1, f"=SUM(B2:B{len(regions)+1})") + +ws.write_formula(len(regions) + 1, 2, f"=SUM(C2:C{len(regions)+1})") + +wb.close() + +Multi-workbook gotchas: + +External references only resolve when both files are open in Excel or when Excel has cached values. + +Python writes the formula string only — no values are cached. On first open, Excel will show \#REF! until the linked file is also open or the link is updated. + +File paths in references can be relative ([file.xlsx]) or absolute ('C:\Reports\\file.xlsx]'). Prefer relative for portability. + +When generating a suite of workbooks, generate all data workbooks first, then the master. + +Google Sheets uses IMPORTRANGE("spreadsheet_url", "Sheet1!A1:B10") instead of bracket syntax. + +Generating a workbook suite + +import xlsxwriter + +regions = {"East": [100, 200, 150], "West": [180, 220, 190], + +"Central": [90, 110, 130]} + +for region, revenues in regions.items(): + +wb = xlsxwriter.Workbook(f"{region.lower()}_data.xlsx") + +ws = wb.add_worksheet("Summary") + +ws.write(0, 0, "Quarter") + +ws.write(0, 1, "Revenue") + +for i, rev in enumerate(revenues, 1): + +ws.write(i, 0, f"Q{i}") + +ws.write(i, 1, rev) + +ws.write(len(revenues) + 1, 0, "Total") + +ws.write_formula(len(revenues) + 1, 1, f"=SUM(B2:B{len(revenues)+1})") + +wb.close() + +Excel Data Tables (Sensitivity Analysis) + +Excel Data Tables (What-If Analysis > Data Table) let you vary one or two inputs and see how an output changes. Python cannot create native data tables, but you can build the equivalent grid of formulas. + +One-Way Data Table + +import xlsxwriter + +wb = xlsxwriter.Workbook("sensitivity_1way.xlsx") + +ws = wb.add_worksheet("Sensitivity") + +ws.write(0, 0, "Revenue") + +ws.write(0, 1, 1000) + +ws.write(1, 0, "Margin") + +ws.write(1, 1, 0.20) + +ws.write(2, 0, "EBITDA") + +ws.write_formula(2, 1, "=B1*B2") + +margins = [0.10, 0.15, 0.20, 0.25, 0.30] + +ws.write(4, 0, "Margin Sensitivity") + +ws.write(5, 0, "Margin") + +ws.write(5, 1, "EBITDA") + +pct*fmt = wb.add*format({"num_format": "0.0%"}) + +money*fmt = wb.add*format({"num_format": '"$"#,##0.0'}) + +for i, margin in enumerate(margins): + +ws.write(6 + i, 0, margin, pct_fmt) + +ws.write*formula(6 + i, 1, f"=B1*A{7+i}", money*fmt) + +wb.close() + +Two-Way Data Table (Sensitivity Grid) + +import xlsxwriter + +wb = xlsxwriter.Workbook("sensitivity_2way.xlsx") + +ws = wb.add_worksheet("IRR Sensitivity") + +hdr = wb.add*format({"bold": True, "bg*color": "#1B3A5C", + +"font_color": "white", "align": "center"}) + +corner = wb.add*format({"bold": True, "bg*color": "#1B3A5C", + +"font*color": "white", "align": "center", "text*wrap": True}) + +pct = wb.add*format({"num*format": "0.0%", "align": "center"}) + +x*fmt = wb.add*format({"num_format": "0.0x", "align": "center"}) + +cell*pct = wb.add*format({"num_format": "0.0%", "align": "center", + +"bg_color": "#F2F2F2"}) + +ws.write(0, 0, "Entry EBITDA") + +ws.write(0, 1, 100) + +ws.write(1, 0, "Equity Invested") + +ws.write(1, 1, 400) + +ws.write(2, 0, "Hold Period") + +ws.write(2, 1, 5) + +exit_multiples = [6.0, 7.0, 8.0, 9.0, 10.0] + +ebitda*growth*rates = [0.00, 0.03, 0.05, 0.08, 0.10, 0.12] + +start_row = 5 + +ws.write(start_row, 0, "EBITDA Growth \\ Exit Multiple", corner) + +for j, mult in enumerate(exit_multiples): + +ws.write(start*row, j + 1, mult, x*fmt) + +for i, growth in enumerate(ebitda*growth*rates): + +r = start_row + 1 + i + +ws.write(r, 0, growth, pct) + +for j, mult in enumerate(exit_multiples): + +ws.write_formula(r, j + 1, + +f"=IFERROR((B1*(1+A{r+1})^B3*{mult}/B2)^(1/B3)-1, 0)", + +cell_pct) + +ws.conditional*format(start*row+1, 1, + +start*row+len(ebitda*growth*rates), len(exit*multiples), { + +"type": "3*color*scale", + +"min_color": "#F8696B", + +"mid_color": "#FFEB84", + +"max_color": "#63BE7B", + +}) + +ws.autofit() + +wb.close() + +Data table tips: + +Always use IFERROR wrappers — edge cases (negative equity, zero denominators) will produce \#DIV/0! or \#NUM!. + +Apply 3-color-scale conditional formatting to make the grid scannable at a glance. + +Label the corner cell clearly (e.g., "Growth \\ Multiple") so users know which axis is which. + +For financial models, common sensitivity pairs: Entry Multiple vs Exit Multiple, Revenue Growth vs EBITDA Margin, WACC vs Terminal Growth. + +Large Dataset Handling + +For datasets exceeding 100K rows, standard openpyxl will consume excessive memory. Use these strategies: + +xlsxwriter (streaming by default) + +import xlsxwriter + +wb = xlsxwriter.Workbook("large*dataset.xlsx", {"constant*memory": True}) + +ws = wb.add_worksheet() + +ws.write_row(0, 0, ["ID", "Name", "Value", "Category", "Date"]) + +for i in range(1, 1*000*001): + +ws.write*row(i, 0, [i, f"Item*{i}", i * 1.5, f"Cat_{i % 10}", "2026-01-01"]) + +wb.close() + +constant_memory: True — reduces RAM usage further by flushing rows to disk. Trade-off: you cannot go back and edit earlier rows. + +openpyxl write-only mode + +from openpyxl import Workbook + +wb = Workbook(write_only=True) + +ws = wb.create_sheet("Data") + +ws.append(["ID", "Name", "Value"]) + +for i in range(1, 500_001): + +ws.append([i, f"Item_{i}", i * 1.5]) + +wb.save("large_openpyxl.xlsx") + +write_only gotchas: + +Cannot read or modify cells after writing — append-only. + +Cannot add tables, merged cells, or conditional formatting. + +Cannot set column widths (use xlsxwriter if you need formatting + large data). + +Chunked reading of large files + +from openpyxl import load_workbook + +wb = load*workbook("huge*file.xlsx", read*only=True, data*only=True) + +ws = wb.active + +batch = [] + +for i, row in enumerate(ws.iter*rows(min*row=2, values_only=True)): + +batch.append(row) + +if len(batch) >= 10_000: + +process_batch(batch) + +batch = [] + +if batch: + +process_batch(batch) + +wb.close() + +pandas chunked processing + +import pandas as pd + +chunks = pd.read*excel("huge*file.xlsx", sheet_name="Data", engine="openpyxl", + +dtype={"ID": int, "Value": float}, + +usecols=["ID", "Name", "Value"]) + +for chunk in pd.read*csv("data.csv", chunksize=50*000): + +process(chunk) + +Performance comparison + +Method Max Rows (practical) RAM for 1M rows Formatting + +xlsxwriter constant_memory 1M+ ~200MB Full + +xlsxwriter normal 1M+ ~500MB Full + +openpyxl write_only 500K ~1GB None + +openpyxl normal 100K ~5GB Full + +pandas to_excel (xlsxwriter) 1M+ ~800MB Via engine + +Decision tree: + +Need formatting + large data -> xlsxwriter with constant_memory: True + +Need to read + modify large file -> openpyxl read_only + process + xlsxwriter output + +Just need data dump -> pandas to_excel with xlsxwriter engine + +Over 1M rows -> split across multiple sheets (Excel limit is 1,048,576 rows per sheet) + +Common Formula Patterns + +Need Formula + +Running total =SUM($B$2:B2) (drag down) + +Lookup (modern) =XLOOKUP(A2, Data!A:A, Data!C:C, "Not found") + +Lookup (compat) =VLOOKUP(A2, Data!A:C, 3, FALSE) + +Conditional sum =SUMIFS(C:C, A:A, "Widget", B:B, ">100") + +Count matching =COUNTIFS(A:A, "Active") + +Percent of total =B2/SUM($B$2:$B$100) + +Safe division =IFERROR(A2/B2, 0) + +Gotcha: When writing formulas from Python, use US-English function names and comma separators regardless of the user's locale. Excel translates on open. + +Number Format Codes + +Format Code + +Currency "$"#,##0.00 + +Thousands \#,##0 + +Percent 0.0% + +Date yyyy-mm-dd + +Negative in red \#,##0;[Red]-#,##0 + +Multiple (e.g. 2.5x) 0.0x + +Millions shorthand \#,##0.0,,"M" + +Accounting (neg in parens) "$"#,##0.00_);[Red]("$"#,##0.00) + +Data Gathering — Use Web Search When Relevant + +Before building the spreadsheet, determine whether the data requires external research. If the user asks for a report, analysis, or dataset about a public company, industry, market, or any publicly available information, use webSearch and webFetch to gather real data first. + +Examples that require web search: + +"Build me a financial model for Tesla" -> search for Tesla's latest 10-K/10-Q, revenue, margins, guidance + +"Create a comp table for SaaS companies" -> search for revenue, ARR, multiples, headcount + +"Make a spreadsheet comparing EV manufacturers" -> search for production numbers, market cap, deliveries + +"Summarize Apple's last 5 quarters" -> search for quarterly earnings data + +Do not fabricate numbers. If you cannot find a specific data point, leave the cell blank or mark it as "N/A -- not found" rather than guessing. Always cite the source (e.g., "Source: Tesla 10-K FY2025") in a notes row or sheet. + +Output + +Always present key findings and recommendations as a plaintext summary in chat, even when also generating files. The user should be able to understand the results without opening any files. + +Limitations + +Cannot write VBA macros (.xlsm requires keep_vba=True in openpyxl to preserve existing macros, not create them) + +Formulas are not computed by Python -- open in Excel/LibreOffice to see results + +openpyxl auto-width is an approximation (no font metrics); xlsxwriter's autofit() is better + +Google Sheets import may drop some conditional formatting and chart styles + +Cannot create native Excel PivotTables -- use formula-based or pandas-based summaries instead + +Cannot create native Excel Data Tables (What-If) -- use formula grids as equivalent + +Cross-workbook references show \#REF! until linked files are opened in Excel + +Excel row limit is 1,048,576 per sheet -- split larger datasets across sheets diff --git a/.local/secondary_skills/excel-generator/financial-models.md b/.local/secondary_skills/excel-generator/financial-models.md new file mode 100644 index 0000000..c85700f --- /dev/null +++ b/.local/secondary_skills/excel-generator/financial-models.md @@ -0,0 +1,289 @@ +# Financial Model Recipes + +Ready-made patterns for common financial models. Each recipe includes the sheet structure, key formulas, and input/output design. + +## 3-Statement Model (Income Statement, Balance Sheet, Cash Flow) + +```python + +import xlsxwriter + +wb = xlsxwriter.Workbook("3_statement_model.xlsx") + +input_fmt = wb.add_format({"bg_color": "#FFF2CC", "border": 1, "num_format": "#,##0.0"}) + +input_pct = wb.add_format({"bg_color": "#FFF2CC", "border": 1, "num_format": "0.0%"}) + +calc_fmt = wb.add_format({"num_format": '"$"#,##0.0', "locked": True}) + +hdr = wb.add_format({"bold": True, "bg_color": "#1B3A5C", "font_color": "white", "bottom": 2}) + +section = wb.add_format({"bold": True, "bg_color": "#D6E4F0", "bottom": 1}) + +total = wb.add_format({"bold": True, "num_format": '"$"#,##0.0', "top": 1, "bottom": 6}) + +YEARS = 5 + +# --- Assumptions Sheet --- + +ws_a = wb.add_worksheet("Assumptions") + +ws_a.set_column(0, 0, 35) + +ws_a.set_column(1, 1, 16) + +assumptions = [ + +("Base Revenue ($M)", 1000, input_fmt, "rev"), + +("Revenue Growth Rate", 0.08, input_pct, "rev_g"), + +("COGS (% of Revenue)", 0.60, input_pct, "cogs_pct"), + +("SG&A (% of Revenue)", 0.15, input_pct, "sga_pct"), + +("D&A (% of Revenue)", 0.03, input_pct, "da_pct"), + +("Interest Rate", 0.05, input_pct, "int_rate"), + +("Tax Rate", 0.25, input_pct, "tax_rate"), + +("Capex (% of Revenue)", 0.05, input_pct, "capex_pct"), + +("Debt Balance ($M)", 500, input_fmt, "debt"), + +("AR Days", 45, wb.add_format({"bg_color": "#FFF2CC", "border": 1, "num_format": "#,##0"}), "ar_days"), + +("Inventory Days", 30, wb.add_format({"bg_color": "#FFF2CC", "border": 1, "num_format": "#,##0"}), "inv_days"), + +("AP Days", 40, wb.add_format({"bg_color": "#FFF2CC", "border": 1, "num_format": "#,##0"}), "ap_days"), + +] + +refs = {} + +for i, (label, val, fmt, key) in enumerate(assumptions): + +ws_a.write(i + 1, 0, label) + +ws_a.write(i + 1, 1, val, fmt) + +refs[key] = f"Assumptions!$B${i+2}" + +# --- Income Statement --- + +ws_is = wb.add_worksheet("Income Statement") + +ws_is.set_column(0, 0, 30) + +ws_is.write_row(0, 1, [f"Year {y}" for y in range(1, YEARS + 1)], hdr) + +rows_is = [ + +("Revenue", f"={refs['rev']}*(1+{refs['rev_g']})^{{y}}", calc_fmt), + +("(-) COGS", f"=-{{rev}}*{refs['cogs_pct']}", calc_fmt), + +("Gross Profit", "={rev}+{cogs}", total), + +("(-) SG&A", f"=-{{rev}}*{refs['sga_pct']}", calc_fmt), + +("(-) D&A", f"=-{{rev}}*{refs['da_pct']}", calc_fmt), + +("EBIT", "={gp}+{sga}+{da}", total), + +("(-) Interest", f"=-{refs['debt']}*{refs['int_rate']}", calc_fmt), + +("EBT", "={ebit}+{interest}", calc_fmt), + +("(-) Taxes", f"=-MAX(0,{{ebt}})*{refs['tax_rate']}", calc_fmt), + +("Net Income", "={ebt}+{taxes}", total), + +] + +# Build row-by-row with formula references pointing to previous rows + +# --- Balance Sheet --- + +ws_bs = wb.add_worksheet("Balance Sheet") + +# Assets: Cash, AR, Inventory, PP&E + +# Liabilities: AP, Debt + +# Equity: Retained Earnings + +# AR = Revenue / 365 * AR Days, Inventory = COGS / 365 * Inv Days, AP = COGS / 365 * AP Days + +# --- Cash Flow Statement --- + +ws_cf = wb.add_worksheet("Cash Flow") + +# Operating: Net Income + D&A + Changes in WC + +# Investing: -Capex + +# Financing: Debt changes, dividends + +# Ending Cash = Beginning + Operating + Investing + Financing + +wb.close() + +``` + +**Key design principles:** + +- Yellow cells = user inputs, all other cells are formulas +- Income Statement drives Balance Sheet (retained earnings) and Cash Flow (net income) + +- Balance Sheet working capital items use days-based formulas tied to revenue/COGS +- Cash Flow reconciles back to Balance Sheet cash line + +## DCF (Discounted Cash Flow) Model + +```python + +# Sheet structure: + +# 1. Assumptions: revenue, growth, margins, WACC, terminal growth, tax rate + +# 2. Projections: 5-10 year operating model + +# 3. DCF Valuation: FCF, discount factors, terminal value, enterprise value, equity bridge + +# Key formulas: + +# Unlevered FCF = EBIT * (1 - Tax) + D&A - Capex - Change in NWC + +# Discount Factor = 1 / (1 + WACC) ^ year + +# PV of FCF = FCF * Discount Factor + +# Terminal Value = Final Year FCF * (1 + g) / (WACC - g) + +# PV of Terminal = Terminal Value * Final Discount Factor + +# Enterprise Value = Sum of PV FCFs + PV of Terminal + +# Equity Value = EV - Net Debt + Cash + +# Per Share = Equity Value / Shares Outstanding + +# Sensitivity table: WACC vs Terminal Growth Rate + +# Use xlsxwriter data table or manual grid of IFERROR formulas + +``` + +**Formula patterns for DCF:** + +| Line Item | Formula | + +|---|---| + +| UFCF | `=EBIT*(1-TaxRate)+DA-Capex-DeltaNWC` | + +| Discount Factor | `=1/(1+WACC)^Year` | + +| PV of FCF | `=UFCF*DiscountFactor` | + +| Terminal Value (Gordon Growth) | `=FinalFCF*(1+TermGrowth)/(WACC-TermGrowth)` | + +| Terminal Value (Exit Multiple) | `=FinalEBITDA*ExitMultiple` | + +| Implied Share Price | `=(SUM(PV_FCFs)+PV_Terminal-NetDebt+Cash)/SharesOut` | + +## LBO (Leveraged Buyout) Model + +```python + +# Sheet structure: + +# 1. Assumptions: entry multiple, capital structure, operating assumptions, exit + +# 2. Sources & Uses: debt tranches, equity, fees + +# 3. Operating Model: revenue, EBITDA, EBIT, net income, FCF + +# 4. Debt Schedule: beginning balance, paydowns (mandatory + sweep), interest, ending balance + +# 5. Returns Analysis: exit EV, equity value, MOIC, IRR + +# Key formulas: + +# Entry EV = LTM EBITDA * Entry Multiple + +# Senior Debt = EBITDA * Senior Turns + +# Sponsor Equity = Total Uses - Total Debt + +# Cash Sweep Paydown = MIN(Beginning Balance, MAX(0, LFCF) * Sweep%) + +# Exit Equity = Exit EV - Net Debt at Exit + Cash + +# MOIC = Exit Equity / Initial Equity + +# IRR = (Exit Equity / Initial Equity) ^ (1 / Years) - 1 + +``` + +## Comparable Company Analysis (Comp Table) + +```python + +# Sheet structure: + +# 1. Company Data: name, ticker, market cap, enterprise value, revenue, EBITDA, net income + +# 2. Multiples: EV/Revenue, EV/EBITDA, P/E, EV/EBIT + +# 3. Summary Stats: mean, median, 25th/75th percentile for each multiple + +# 4. Implied Valuation: apply median multiples to target company metrics + +# Key formulas: + +# EV/Revenue = Enterprise Value / LTM Revenue + +# EV/EBITDA = Enterprise Value / LTM EBITDA + +# Implied EV = Target Metric * Median Multiple + +# Mean = AVERAGE(range), Median = MEDIAN(range) + +# Percentiles = PERCENTILE.INC(range, 0.25) and PERCENTILE.INC(range, 0.75) + +``` + +## Merger Model (M&A Accretion/Dilution) + +```python + +# Sheet structure: + +# 1. Acquirer Standalone: EPS, shares out, P/E, net income + +# 2. Target Standalone: same metrics + +# 3. Deal Assumptions: offer price, premium, % cash vs stock, synergies, integration costs + +# 4. Pro Forma: combined net income + synergies - financing costs, new share count + +# 5. Accretion/Dilution: (Pro Forma EPS - Acquirer EPS) / Acquirer EPS + +# Key formulas: + +# New Shares Issued = (Offer Price * Target Shares * Stock%) / Acquirer Share Price + +# Pro Forma Shares = Acquirer Shares + New Shares + +# Financing Cost = Offer Price * Target Shares * Cash% * Interest Rate * (1 - Tax) + +# Pro Forma NI = Acquirer NI + Target NI + Synergies - Integration - Financing Cost + +# Pro Forma EPS = Pro Forma NI / Pro Forma Shares + +# Accretion = (Pro Forma EPS / Acquirer EPS) - 1 + +``` diff --git a/.local/secondary_skills/file-converter/.fingerprint b/.local/secondary_skills/file-converter/.fingerprint new file mode 100644 index 0000000..d272230 --- /dev/null +++ b/.local/secondary_skills/file-converter/.fingerprint @@ -0,0 +1 @@ +5f93e7bfd8de5af87ed9a62a23b6f6d5 \ No newline at end of file diff --git a/.local/secondary_skills/file-converter/SKILL.md b/.local/secondary_skills/file-converter/SKILL.md new file mode 100644 index 0000000..1a66bd4 --- /dev/null +++ b/.local/secondary_skills/file-converter/SKILL.md @@ -0,0 +1,823 @@ +--- +name: file-converter +description: Convert, merge, split, and compress files across formats — documents, images, audio, and more. +--- + +# File Converter + +Convert between data, document, image, audio formats, and ZIP archives. One-liners for each conversion pair. + +## Tool Map + +| Domain | Tool | Install | + +|---|---|---| + +| CSV/JSON/Excel/Parquet | `pandas` | `pip install pandas openpyxl pyarrow` | + +| YAML | `pyyaml` | `pip install pyyaml` | + +| XML ↔ dict | `xmltodict` | `pip install xmltodict` | + +| Any doc format ↔ any | **pandoc** (CLI) | `apt install pandoc` or `pip install pypandoc_binary` | + +| Markdown → HTML | `markdown` | `pip install markdown` | + +| HTML → Markdown | `markdownify` | `pip install markdownify` | + +| .docx read/write | `python-docx` | `pip install python-docx` | + +| PDF → text/tables | `pdfplumber` | `pip install pdfplumber` | + +| PDF → images | `pdf2image` | `pip install pdf2image` + `apt install poppler-utils` | + +| PDF manipulation | `pypdf` | `pip install pypdf` | + +| Images | `Pillow` | `pip install Pillow` | + +| SVG → PNG | `cairosvg` | `pip install cairosvg` | + +| HEIC → JPG | `pillow-heif` | `pip install pillow-heif` | + +| Audio formats | `pydub` | `pip install pydub` + `apt install ffmpeg` | + +| EPUB ↔ other | **pandoc** or `ebooklib` | `pip install ebooklib` | + +| HTML → PDF | `weasyprint` | `pip install weasyprint` | + +| GIF creation | `Pillow` or `imageio` | `pip install imageio[ffmpeg]` | + +| PDF → SVG | `pdf2image` + `potrace` or `pymupdf` | `pip install pymupdf` | + +| ZIP archives | `zipfile` (stdlib) | built-in, no install needed | + +## File Input Handling + +When a user wants to convert a file that can't be attached directly in the chat (e.g., `.heic`, `.flac`, `.epub`, `.psd`, `.m4a`, `.wma`, `.parquet`), ask them to upload it to the project's file system. Uploaded files typically appear in `attached_assets/` or the project root. Always check both locations. If the file isn't found, ask the user where they saved it. + +Common unsupported-in-chat but convertible formats: `.heic`, `.avif`, `.webp`, `.flac`, `.ogg`, `.m4a`, `.wma`, `.aiff`, `.epub`, `.parquet`, `.psd`, `.svg`, `.zip` + +## Data Formats + +```python + +import pandas as pd, json, yaml, xmltodict + +# --- CSV ↔ JSON --- + +pd.read_csv("in.csv").to_json("out.json", orient="records", indent=2) + +pd.read_json("in.json").to_csv("out.csv", index=False) + +# --- CSV → Excel / Excel → CSV --- + +pd.read_csv("in.csv").to_excel("out.xlsx", index=False, engine="openpyxl") + +pd.read_excel("in.xlsx", sheet_name="Sheet1").to_csv("out.csv", index=False) + +# All sheets: pd.read_excel("in.xlsx", sheet_name=None) → dict of DataFrames + +# --- CSV → Parquet (columnar, compressed) --- + +pd.read_csv("in.csv").to_parquet("out.parquet", engine="pyarrow", compression="snappy") + +# --- YAML ↔ JSON --- + +data = yaml.safe_load(open("in.yaml")) \# ALWAYS safe_load, never load() + +json.dump(data, open("out.json", "w"), indent=2) + +yaml.safe_dump(json.load(open("in.json")), open("out.yaml", "w"), sort_keys=False) + +# --- XML ↔ JSON --- + +data = xmltodict.parse(open("in.xml").read()) + +json.dump(data, open("out.json", "w"), indent=2) + +open("out.xml", "w").write(xmltodict.unparse(data, pretty=True)) + +# --- JSONL (one JSON object per line) --- + +pd.read_json("in.jsonl", lines=True).to_csv("out.csv", index=False) + +``` + +**Encoding gotchas:** + +- `pd.read_csv("f.csv", encoding="utf-8-sig")` strips the BOM that Excel inserts +- Auto-detect: `import chardet; enc = chardet.detect(open("f.csv","rb").read())["encoding"]` + +- CSV delimiter sniffing: `pd.read_csv("f.csv", sep=None, engine="python")` + +**Nested JSON → flat CSV:** + +```python + +pd.json_normalize(data, sep=".").to_csv("out.csv", index=False) \# {"a":{"b":1}} → column "a.b" + +``` + +## Document Formats — pandoc is the Swiss Army knife + +```bash + +# Markdown → PDF (requires LaTeX: apt install texlive-xetex) + +pandoc input.md -o output.pdf --pdf-engine=xelatex + +# Markdown → DOCX + +pandoc input.md -o output.docx + +# DOCX → Markdown (extracts images to ./media/) + +pandoc input.docx -o output.md --extract-media=. + +# HTML → Markdown + +pandoc input.html -o output.md -t gfm + +# Any → Any (pandoc supports ~40 formats) + +pandoc -f docx -t rst input.docx -o output.rst + +``` + +```python + +# From Python + +import pypandoc + +pypandoc.convert_file("in.md", "docx", outputfile="out.docx") + +``` + +**Without pandoc (pure Python):** + +```python + +# Markdown → HTML + +import markdown + +html = markdown.markdown(open("in.md").read(), extensions=["tables", "fenced_code", "toc"]) + +# HTML → Markdown + +from markdownify import markdownify + +md = markdownify(html, heading_style="ATX") \# ATX = \# headers, not underlines + +``` + +## PDF Operations + +```python + +# --- Extract text + tables --- + +import pdfplumber + +with pdfplumber.open("in.pdf") as pdf: + +text = "\n".join(p.extract_text() or "" for p in pdf.pages) + +tables = pdf.pages[0].extract_tables() \# list of list-of-rows + +# --- PDF → images (one PNG per page) --- + +from pdf2image import convert_from_path + +for i, img in enumerate(convert_from_path("in.pdf", dpi=200)): + +img.save(f"page_{i+1}.png") + +# --- Merge / split / rotate --- + +from pypdf import PdfReader, PdfWriter + +writer = PdfWriter() + +for path in ["a.pdf", "b.pdf"]: + +for page in PdfReader(path).pages: + +writer.add_page(page) + +writer.write("merged.pdf") + +# Extract pages 2–5 + +reader = PdfReader("in.pdf") + +writer = PdfWriter() + +for p in reader.pages[1:5]: + +writer.add_page(p) + +writer.write("pages_2-5.pdf") + +``` + +**PDF gotchas:** + +- `pdf2image` needs `poppler-utils` installed system-wide (not a pip package) +- Scanned PDFs have no text layer — pdfplumber returns `None`. Use `pytesseract` OCR on pdf2image output. + +- `PyPDF2` is deprecated → use `pypdf` (same API, maintained fork) + +## Image Formats + +```python + +from PIL import Image + +# --- Basic conversion --- + +Image.open("in.png").convert("RGB").save("out.jpg", quality=90) + +# convert("RGB") is REQUIRED: JPEG can't store alpha channel, will raise OSError + +# --- WebP (best web format) --- + +Image.open("in.jpg").save("out.webp", quality=85, method=6) \# method 0-6, 6=best compression + +# --- AVIF (smallest, Pillow 11+) --- + +Image.open("in.jpg").save("out.avif", quality=75) + +# --- HEIC (iPhone photos) → JPG --- + +from pillow_heif import register_heif_opener + +register_heif_opener() + +Image.open("in.heic").convert("RGB").save("out.jpg", quality=90) + +# --- SVG → PNG --- + +import cairosvg + +cairosvg.svg2png(url="in.svg", write_to="out.png", output_width=1024) + +# --- Batch convert directory --- + +from pathlib import Path + +for p in Path("imgs").glob("*.png"): + +Image.open(p).convert("RGB").save(p.with_suffix(".jpg"), quality=85) + +``` + +**Image gotchas:** + +- PNG → JPG: **must** `convert("RGB")` first or transparency crashes the save +- `quality` for PNG is meaningless (lossless) — use `optimize=True, compress_level=9` + +- Pillow can't open `.svg` natively — use `cairosvg` or `svglib` +- GIF → MP4 is a video operation: `ffmpeg -i in.gif -pix_fmt yuv420p out.mp4` + +## Audio Formats + +```python + +from pydub import AudioSegment + +# --- MP3 ↔ WAV --- + +AudioSegment.from_mp3("in.mp3").export("out.wav", format="wav") + +AudioSegment.from_wav("in.wav").export("out.mp3", format="mp3", bitrate="192k") + +# --- FLAC → MP3 --- + +AudioSegment.from_file("in.flac", format="flac").export("out.mp3", format="mp3", bitrate="320k") + +# --- OGG → MP3 --- + +AudioSegment.from_ogg("in.ogg").export("out.mp3", format="mp3", bitrate="192k") + +# --- M4A / AAC → MP3 --- + +AudioSegment.from_file("in.m4a", format="m4a").export("out.mp3", format="mp3", bitrate="256k") + +# --- Any → Any (pydub supports mp3, wav, ogg, flac, m4a, aac, wma, aiff) --- + +AudioSegment.from_file("in.wma", format="wma").export("out.flac", format="flac") + +# --- Trim audio (first 30 seconds) --- + +audio = AudioSegment.from_file("in.mp3") + +audio[:30000].export("first_30s.mp3", format="mp3") \# milliseconds + +# --- Merge / concatenate --- + +combined = AudioSegment.from_file("a.mp3") + AudioSegment.from_file("b.mp3") + +combined.export("merged.mp3", format="mp3") + +# --- Adjust volume --- + +audio = AudioSegment.from_file("in.mp3") + +louder = audio + 6 \# +6 dB + +quieter = audio - 6 \# -6 dB + +louder.export("louder.mp3", format="mp3") + +# --- Get audio info --- + +audio = AudioSegment.from_file("in.mp3") + +print(f"Duration: {len(audio)/1000:.1f}s, Channels: {audio.channels}, " + +f"Sample rate: {audio.frame_rate}Hz, Sample width: {audio.sample_width*8}bit") + +# --- Batch convert directory --- + +from pathlib import Path + +for p in Path("audio").glob("*.wav"): + +AudioSegment.from_wav(str(p)).export(p.with_suffix(".mp3"), format="mp3", bitrate="192k") + +``` + +**Audio gotchas:** + +- `pydub` requires `ffmpeg` installed system-wide for non-WAV formats +- Bitrate options: "128k" (small/low quality), "192k" (balanced), "256k" (high), "320k" (max for MP3) + +- WAV files are uncompressed — expect 10x larger file sizes than MP3 +- For sample rate conversion: `audio.set_frame_rate(44100).export("out.wav", format="wav")` + +- Mono to stereo: `audio.set_channels(2)` / Stereo to mono: `audio.set_channels(1)` + +## ZIP Archives + +```python + +import zipfile + +from pathlib import Path + +# --- Create ZIP from files --- + +with zipfile.ZipFile("archive.zip", "w", zipfile.ZIP_DEFLATED) as zf: + +zf.write("file1.txt") + +zf.write("file2.csv") + +zf.write("images/photo.jpg") + +# --- Create ZIP from entire directory --- + +import shutil + +shutil.make_archive("archive", "zip", root_dir="my_folder") \# creates archive.zip + +# --- Extract all --- + +with zipfile.ZipFile("archive.zip", "r") as zf: + +zf.extractall("output_dir") + +# --- Extract single file --- + +with zipfile.ZipFile("archive.zip", "r") as zf: + +zf.extract("file1.txt", "output_dir") + +# --- List contents without extracting --- + +with zipfile.ZipFile("archive.zip", "r") as zf: + +for info in zf.infolist(): + +print(f"{info.filename} {info.file_size:,} bytes {info.compress_size:,} compressed") + +# --- Read file from ZIP without extracting --- + +with zipfile.ZipFile("archive.zip", "r") as zf: + +content = zf.read("file1.txt").decode("utf-8") + +# --- Add files to existing ZIP --- + +with zipfile.ZipFile("archive.zip", "a") as zf: + +zf.write("new_file.txt") + +# --- Create ZIP with password (read-only, use pyzipper for write) --- + +# pip install pyzipper + +import pyzipper + +with pyzipper.AESZipFile("secure.zip", "w", compression=pyzipper.ZIP_DEFLATED, + +encryption=pyzipper.WZ_AES) as zf: + +zf.setpassword(b"my_password") + +zf.write("secret.txt") + +# --- Batch: ZIP all PDFs in a directory --- + +with zipfile.ZipFile("all_pdfs.zip", "w", zipfile.ZIP_DEFLATED) as zf: + +for p in Path(".").glob("**/*.pdf"): + +zf.write(p) + +``` + +**ZIP gotchas:** + +- `zipfile` is in Python's standard library — no install needed +- Always use `ZIP_DEFLATED` compression (default is `ZIP_STORED` = no compression) + +- For password-protected ZIPs, stdlib `zipfile` can only read (not write) — use `pyzipper` for encrypted writes +- Max file size in standard ZIP is 4 GB; use `allowZip64=True` (default in Python 3) for larger files + +- `shutil.make_archive` is the simplest way to ZIP an entire directory tree + +## EPUB Formats + +```python + +# --- EPUB → other formats (via pandoc) --- + +# pandoc is the easiest way to convert EPUB + +import pypandoc + +# EPUB → Markdown + +pypandoc.convert_file("in.epub", "markdown", outputfile="out.md") + +# EPUB → HTML + +pypandoc.convert_file("in.epub", "html", outputfile="out.html") + +# EPUB → DOCX + +pypandoc.convert_file("in.epub", "docx", outputfile="out.docx") + +# EPUB → plain text + +pypandoc.convert_file("in.epub", "plain", outputfile="out.txt") + +# --- Other formats → EPUB --- + +# Markdown → EPUB + +pypandoc.convert_file("in.md", "epub", outputfile="out.epub", + +extra_args=["--metadata", "title=My Book"]) + +# HTML → EPUB + +pypandoc.convert_file("in.html", "epub", outputfile="out.epub", + +extra_args=["--metadata", "title=My Book"]) + +# DOCX → EPUB + +pypandoc.convert_file("in.docx", "epub", outputfile="out.epub") + +``` + +```bash + +# --- CLI equivalents --- + +pandoc in.epub -o out.md + +pandoc in.epub -o out.pdf --pdf-engine=xelatex + +pandoc in.md -o out.epub --metadata title="My Book" + +pandoc in.html -o out.epub --metadata title="My Book" --epub-cover-image=cover.jpg + +``` + +```python + +# --- Pure Python: read/write EPUB with ebooklib --- + +from ebooklib import epub + +# Read EPUB + +book = epub.read_epub("in.epub") + +for item in book.get_items_of_type(9): \# 9 = ITEM_DOCUMENT (HTML chapters) + +print(item.get_name()) + +html_content = item.get_content().decode("utf-8") + +# Create EPUB from scratch + +book = epub.EpubBook() + +book.set_identifier("id123") + +book.set_title("My Book") + +book.set_language("en") + +book.add_author("Author Name") + +ch1 = epub.EpubHtml(title="Chapter 1", file_name="ch1.xhtml", lang="en") + +ch1.content = "

Chapter 1

Hello world.

" + +book.add_item(ch1) + +book.toc = [epub.Link("ch1.xhtml", "Chapter 1", "ch1")] + +book.add_item(epub.EpubNcx()) + +book.add_item(epub.EpubNav()) + +book.spine = ["nav", ch1] + +epub.write_epub("out.epub", book) + +``` + +**EPUB gotchas:** + +- `pandoc` is the simplest for format-to-format EPUB conversion +- Always add `--metadata title="..."` when creating EPUB — readers require a title + +- EPUB is essentially a ZIP of HTML files — `ebooklib` gives you fine-grained control +- For EPUB → PDF, pandoc needs a LaTeX engine (`texlive-xetex`) + +- Cover images: use `--epub-cover-image=cover.jpg` with pandoc + +## HTML to PDF + +```python + +# --- weasyprint (best CSS support, no browser needed) --- + +from weasyprint import HTML + +# Simple file conversion + +HTML("in.html").write_pdf("out.pdf") + +# From URL + +HTML("https://example.com").write_pdf("page.pdf") + +# From HTML string + +HTML(string="

Hello

World

").write_pdf("out.pdf") + +# With custom CSS + +HTML("in.html").write_pdf("out.pdf", stylesheets=["custom.css"]) + +# With page size and margins + +from weasyprint import CSS + +HTML("in.html").write_pdf("out.pdf", stylesheets=[ + +CSS(string="@page { size: A4; margin: 2cm; }") + +]) + +# Landscape orientation + +HTML("in.html").write_pdf("out.pdf", stylesheets=[ + +CSS(string="@page { size: A4 landscape; margin: 1.5cm; }") + +]) + +``` + +```bash + +# --- CLI alternatives --- + +# pandoc (simpler, less CSS fidelity) + +pandoc in.html -o out.pdf --pdf-engine=xelatex + +# weasyprint CLI + +weasyprint in.html out.pdf + +weasyprint https://example.com page.pdf + +``` + +**HTML to PDF gotchas:** + +- `weasyprint` supports CSS3 including flexbox, grid, and `@page` rules — best for styled documents +- `weasyprint` does NOT run JavaScript — for JS-heavy pages, use `playwright` or `pyppeteer` instead + +- For JS-rendered pages: `playwright` → `page.pdf()` is the most reliable option +- pandoc HTML → PDF goes through LaTeX, so complex CSS layouts may not render correctly + +- Large HTML files with many images: use `HTML(filename="in.html", base_url=".")` so relative image paths resolve + +## GIF Creation + +```python + +from PIL import Image + +import imageio.v3 as iio + +from pathlib import Path + +# --- Images → animated GIF (Pillow) --- + +frames = [Image.open(f"frame_{i}.png") for i in range(10)] + +frames[0].save("out.gif", save_all=True, append_images=frames[1:], + +duration=100, loop=0) \# duration in ms, loop=0 means infinite + +# --- Images → GIF with optimization --- + +frames = [Image.open(f"frame_{i}.png").convert("RGBA") for i in range(10)] + +frames[0].save("out.gif", save_all=True, append_images=frames[1:], + +duration=100, loop=0, optimize=True) + +# --- Directory of images → GIF --- + +frame_paths = sorted(Path("frames").glob("*.png")) + +frames = [Image.open(p) for p in frame_paths] + +frames[0].save("out.gif", save_all=True, append_images=frames[1:], + +duration=100, loop=0) + +# --- GIF → individual frames --- + +gif = Image.open("in.gif") + +for i in range(gif.n_frames): + +gif.seek(i) + +gif.save(f"frame_{i}.png") + +# --- Resize GIF --- + +gif = Image.open("in.gif") + +resized_frames = [] + +for i in range(gif.n_frames): + +gif.seek(i) + +resized_frames.append(gif.copy().resize((320, 240), Image.LANCZOS)) + +resized_frames[0].save("small.gif", save_all=True, append_images=resized_frames[1:], + +duration=gif.info.get("duration", 100), loop=0) + +# --- Video → GIF (imageio + ffmpeg) --- + +import imageio.v3 as iio + +frames = iio.imread("in.mp4", plugin="pyav") + +iio.imwrite("out.gif", frames, plugin="pillow", duration=40, loop=0) + +# --- GIF → MP4 (ffmpeg CLI, much smaller file) --- + +# ffmpeg -i in.gif -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" out.mp4 + +``` + +**GIF gotchas:** + +- GIF is limited to 256 colors per frame — complex images lose quality +- Use `optimize=True` to reduce file size, but large GIFs are still huge compared to MP4 + +- `duration` is per-frame in milliseconds (100ms = 10 FPS, 40ms = 25 FPS) +- `loop=0` means infinite loop; `loop=1` plays once then stops + +- For video → GIF, consider downscaling first — full-resolution GIFs are enormous +- Pillow GIF output doesn't support transparency well — use `imageio` for better results + +- For best quality: create GIF from video with ffmpeg: `ffmpeg -i in.mp4 -vf "fps=15,scale=480:-1" out.gif` + +## PDF to SVG + +```python + +# --- PyMuPDF (fitz) — best quality, vector-preserving --- + +import fitz \# pip install pymupdf + +# Single page + +doc = fitz.open("in.pdf") + +page = doc[0] + +svg_text = page.get_svg_image() + +with open("page_1.svg", "w") as f: + +f.write(svg_text) + +# All pages + +doc = fitz.open("in.pdf") + +for i, page in enumerate(doc): + +svg_text = page.get_svg_image() + +with open(f"page_{i+1}.svg", "w") as f: + +f.write(svg_text) + +doc.close() + +# With custom resolution (matrix scales the output) + +doc = fitz.open("in.pdf") + +page = doc[0] + +mat = fitz.Matrix(2, 2) \# 2x scale for higher detail + +svg_text = page.get_svg_image(matrix=mat) + +with open("page_hires.svg", "w") as f: + +f.write(svg_text) + +``` + +```bash + +# --- CLI alternatives --- + +# pdf2svg (if installed) + +pdf2svg in.pdf out.svg 1 \# page number + +# Inkscape CLI + +inkscape in.pdf --export-type=svg --export-filename=out.svg + +# pdftocairo (from poppler-utils) + +pdftocairo -svg in.pdf out.svg + +``` + +**PDF to SVG gotchas:** + +- `pymupdf` (imported as `fitz`) produces true vector SVGs — text stays as text, paths stay as paths +- Scanned PDFs produce SVGs with embedded raster images (no vector data to extract) + +- Large PDFs with complex graphics produce very large SVG files +- `pdf2svg` CLI tool is simple but must be installed separately (`apt install pdf2svg`) + +- For rasterized SVG (simpler but not truly vector): render PDF to PNG first, then embed in SVG + +## Validation + +Always verify output: + +```python + +# Row count parity + +assert len(pd.read_csv("out.csv")) == len(pd.read_json("in.json")) + +# JSON well-formed + +json.load(open("out.json")) + +# Image opens + +Image.open("out.jpg").verify() + +``` diff --git a/.local/secondary_skills/flashcard-generator/.fingerprint b/.local/secondary_skills/flashcard-generator/.fingerprint new file mode 100644 index 0000000..25fc69e --- /dev/null +++ b/.local/secondary_skills/flashcard-generator/.fingerprint @@ -0,0 +1 @@ +446c4f0b199781c8ce744d0532529de8 \ No newline at end of file diff --git a/.local/secondary_skills/flashcard-generator/SKILL.md b/.local/secondary_skills/flashcard-generator/SKILL.md new file mode 100644 index 0000000..4164d54 --- /dev/null +++ b/.local/secondary_skills/flashcard-generator/SKILL.md @@ -0,0 +1,233 @@ +--- +name: flashcard-generator +description: Generate flashcards, quizzes, and study guides from notes or topics. +--- + +# Flashcard & Quiz Generator + +Generate study materials grounded in memory science. Follow Wozniak's formulation rules, schedule with SM-2, export to Anki via `genanki`. + +## When to Use + +- User pastes notes/textbook content to convert to cards, needs exam prep, or wants an Anki deck + +## When NOT to Use + +- In-depth research (deep-research), data analysis (data-analysis) + +## Why Spaced Repetition Works + +Ebbinghaus (1885) showed memory decays as `R = e^(-t/S)`where`S`is memory stability — without review, ~50-70% of new information is gone within 24 hours. The curve was replicated in 2015 (Murre & Dros, PLOS ONE). Each successful recall increases`S`, flattening the curve. **The core insight: reviewing just before you'd forget is the most efficient moment to review.** Active recall (retrieving the answer) builds stability far more than passive re-reading — this is why cards beat highlighting. + +## Card Formulation: Wozniak's 20 Rules + +Piotr Wozniak (SuperMemo creator; Anki forked his SM-2 algorithm) published the canonical rules in 1999 at supermemo.com. The ones that matter most for card generation: + +**Rule 1-2: Understand before you memorize.** Don't make cards for material the user hasn't grasped yet. Cards reinforce; they don't teach. + +**Rule 4: Minimum Information Principle — the single most important rule.** One atomic fact per card. Complex cards get forgotten as a unit — if any part fails, the whole card resets. Split aggressively. + +- Bad: `Q: What are the three branches of US government and what does each do?` (6 facts, fails together) +- Good: Six cards. `Q: Which branch of US government writes laws? A: Legislative` Ɨ each branch Ɨ each function. + +**Rule 5: Cloze deletion is the fastest path from prose to cards.** Take a sentence, blank one term. Beginners who struggle with minimum-information should default to cloze. + +- Source: `TCP guarantees ordered delivery; UDP does not.` +- Cards: `{{c1::TCP}} guarantees ordered delivery; {{c2::UDP}} does not.` → 2 cards from one sentence + +**Rule 9-10: Avoid sets and enumerations.**"List all 7 OSI layers" is a nightmare card — high failure rate, painful reviews. Instead, use**overlapping cloze**: one sentence with the full list, generate N cards each blanking one item. The redundancy is intentional — it's extra *cards*, not extra info per card. + +**Rule 11: Combat interference.** Similar cards confuse each other (`affect`vs`effect`, port 80 vs 443). Add disambiguating context:`Q: [web, unencrypted] Default HTTP port? A: 80`. + +**Rule 14: Personalize.** `Q: What's O(n log n)? A: Merge sort — like the algorithm you botched in the Stripe interview` sticks better than the abstract definition. + +**The diagnostic:** If a card's ease factor drops below 1.3 in review, the card is malformed, not hard. Rewrite it, don't grind it. + +## Card Types + +| Type | Use for | Example | + +|---|---|---| + +| **Basic Q→A** | Single facts | `Q: Capital of Mongolia? A: Ulaanbaatar` | + +| **Cloze** | Converting prose fast; lists | `The {{c1::mitochondria}} produces {{c2::ATP}} via {{c3::oxidative phosphorylation}}` → 3 cards | + +| **Reversed** | Bidirectional recall (vocab) | Generates both `fr→en`and`en→fr` | + +| **Application** | Understanding, not recall | `Q: Revenue +20%, profit āˆ’5%. Why? A: Costs grew faster than revenue` | + +| **Image occlusion** | Anatomy, diagrams, maps | Blank one label on a diagram per card (Wozniak rule 8) | + +Mix Bloom's levels: ~40% remember (basic/cloze), ~30% understand, ~30% apply/analyze. Pure recall decks feel productive but fail on exams that test transfer. + +## SM-2 Scheduling (What Anki Runs) + +Wozniak's 1987 algorithm. Each card tracks three values: repetition count `n`, ease factor`EF`(starts at 2.5), interval`I` in days. After each review, grade 0-5: + +```text + +if grade >= 3: \# correct + +if n == 0: I = 1 + +elif n == 1: I = 6 + +else: I = round(I * EF) \# exponential growth + +n += 1 + +else: \# forgot + +n = 0; I = 1 \# reset interval, keep EF + +EF += 0.1 - (5-grade) * (0.08 + (5-grade)*0.02) + +EF = max(EF, 1.3) \# floor — below this, card is malformed + +``` + +Grade 5 → EF +0.10. Grade 4 → no change. Grade 3 → EF āˆ’0.14. A card you always rate "good" (4) with EF 2.5 goes: 1 → 6 → 15 → 38 → 94 days. **FSRS** (Anki 23.10+) is the ML successor — fits a personal forgetting curve, ~20-30% fewer reviews for same retention. Mention it; default to SM-2 for simplicity. + +## Export to Anki: `genanki` + +`pip install genanki`(github.com/kerrickstaley/genanki). Generates`.apkg` files that import directly via File → Import. + +```python + +import genanki, random + +# Generate these ONCE, then hardcode — stable IDs let users re-import updates + +MODEL_ID = random.randrange(1 << 30, 1 << 31) \# e.g. 1607392319 + +DECK_ID = random.randrange(1 << 30, 1 << 31) + +basic = genanki.Model(MODEL_ID, 'Basic', + +fields=[{'name': 'Q'}, {'name': 'A'}], + +templates=[{'name': 'Card 1', 'qfmt': '{{Q}}', + +'afmt': '{{FrontSide}}
{{A}}'}], + +css='.card { font-family: Arial; font-size: 20px; text-align: center; }') + +deck = genanki.Deck(DECK_ID, 'Biology :: Cell Structure') + +deck.add_note(genanki.Note(model=basic, + +fields=['What organelle produces ATP?', 'Mitochondria'])) + +# Cloze uses built-in model — second field required (can be empty) since 0.13.0 + +deck.add_note(genanki.Note(model=genanki.builtin_models.CLOZE_MODEL, + +fields=['The {{c1::mitochondria}} produces {{c2::ATP}}', ''])) + +genanki.Package(deck).write_to_file('cells.apkg') + +``` + +**Gotchas:** Fields are HTML — `html.escape()`any user content with`<`,`>`,`&`. For images/audio, set`package.media_files = ['diagram.png']`and reference by **basename only** in the field:``(paths break). Stable GUIDs let re-imports update cards in place — subclass`Note`and override`guid` to hash only the question field. + +**Quizlet/CSV fallback:** Tab-separated, one card per line: `question\tanswer\n`. Quizlet imports directly. Also works for Anki's File → Import → Text. + +## Output: Always Build a Web App + +**Every flashcard generation MUST produce an interactive web app as the primary output.**Do not output cards as plain text or markdown — always build a React + Vite single-page app with**two modes** the user can switch between: + +### Mode 1: Flashcard Review + +1. **Card display** — show front of card, flip to back on click or spacebar +2. **SM-2 grading**— four buttons: Again (1), Hard (3), Good (4), Easy (5), wired to the SM-2 algorithm above.**Grading and accuracy:** grades 3-5 (Hard, Good, Easy) count as "correct"; grade 1 (Again) counts as "incorrect". Accuracy is calculated per session as `(correct / reviewed) * 100`. This resets on page reload; review progress (intervals, due dates) persists in localStorage. + +3. **Spaced repetition queue** — `localStorage`persistence for`{cardId: {n, EF, I, due}}`. **Card ordering:**previously reviewed cards that are due appear first, sorted by due date (most overdue first). New (unseen) cards are**shuffled randomly each session**using**Fisher-Yates shuffle** (the only unbiased O(n) shuffle algorithm — naive`array.sort(() => Math.random() - 0.5)` produces biased distributions). Never present new cards in a fixed order — it creates a false sense of learning tied to sequence rather than recall. +4. **Session stats** — cards reviewed, accuracy %, cards due tomorrow, total remaining + +5. **Card type support** — render Basic Q→A, Cloze (hide blanked terms), and Reversed cards correctly +6. **Flip animation** — CSS 3D transform, keyboard shortcuts (Space to flip, 1/2/3/4 for grading) + +7. **Card difficulty indicators** — show a visual indicator (colored dot or badge) on each card based on its current ease factor. Green for EF ≄ 2.5 (easy), yellow for 1.8 ≤ EF < 2.5 (moderate), red for EF < 1.8 (hard). Helps users see at a glance which cards they're mastering vs. struggling with. +8. **Leech detection** — track how many times a card has been graded Again (1). If a card is reset more than 4 times, flag it as a "leech" with a visual warning (e.g., a āš ļø icon). Leeches are almost always malformed cards that should be rewritten, not drilled harder. Optionally offer a "Rewrite this card" prompt. + +9. **Daily new card limit** — enforce a configurable daily limit for new (unseen) cards, defaulting to 20. Store the count in localStorage with today's date. Once the limit is reached, only show review cards. This prevents users from overwhelming themselves — the review debt from too many new cards becomes unsustainable by week 3. +10. **Study streak** — track consecutive days of study in localStorage. Display a streak counter (e.g., "šŸ”„ 5-day streak") in the session stats area. A day counts if the user reviews at least 1 card. Streaks reset if a day is missed. Streaks are a proven motivator for building daily review habits. + +### Mode 2: AI Quiz + +An AI-powered quiz mode that generates and grades questions: + +1. **Quiz setup** — user picks a topic (or all topics) and number of questions (5, 10, 20, custom) +2. **Question generation**— use AI integrations to generate N questions from the card material. Mix question types: multiple choice, short answer, and true/false. Questions should test understanding and application, not just recall.**Difficulty progression:** start with easier recall-level questions and ramp up to application/analysis questions as the quiz progresses. This builds confidence and mirrors real exam structure. + +3. **Answer & grade** — user answers each question, then AI grades the response with a score and explanation of what was right/wrong +4. **Quiz results** — summary screen with overall score, per-question breakdown, and which topics need more work + +5. **Weak spot feedback**— highlight topics where the user scored lowest and suggest reviewing those flashcards.**Link back to flashcard mode:** include a "Review these cards" button next to weak topics that switches to flashcard mode pre-filtered to that topic. This closes the learn-test-review loop. + +### Mode 3 (Optional): Card Import from Notes + +If the user wants to create their own cards, offer a text import mode: + +1. **Paste area** — user pastes notes, bullet points, or prose into a text area +2. **AI card generation** — use AI integrations to parse the text and generate flashcards following Wozniak's minimum information principle. Output Basic Q→A and Cloze cards. + +3. **Review before adding** — show the generated cards in an editable list. Let the user approve, edit, or delete each card before adding to the deck. +4. **Merge into deck** — approved cards get added to the main deck with fresh SM-2 state (n=0, EF=2.5, I=0). + +### UI/UX Requirements + +- **Tab or toggle** to switch between Flashcard and Quiz modes +- **Clean, focused design** — one card or question centered on screen, no clutter + +- **Mobile-friendly** — responsive layout, touch targets +- **Topic/deck selector** — filter by topic in both modes + +- **Progress indicator** — card counter in flashcard mode, question progress bar in quiz mode +- **Progress history** — store daily review counts and accuracy in localStorage. Optionally display a simple chart or heatmap showing review activity over the past 30 days. This gives users a sense of long-term progress beyond the current session. + +## Best Practices + +1. **Minimum information principle trumps everything** — when in doubt, split the card +2. **Cloze is the default for prose** — fastest path from notes to reviewable cards + +3. **Never make set-enumeration cards** — "list all X" → overlapping cloze instead +4. **30 great cards > 100 mediocre ones** — review burden compounds; every bad card costs minutes over months + +5. **Cap new cards at ~20/day** — the review debt from 100 new cards/day becomes unsustainable by week 3 +6. **Interleave topics in the card data array** — when hardcoding cards, mix topics throughout the array rather than grouping all cards of one topic together. Even with shuffle logic, interleaving ensures better variety if the shuffle ever fails or is bypassed + +## Technical Notes + +- **Fisher-Yates shuffle implementation:** When shuffling new cards, always use the Fisher-Yates (Knuth) algorithm. The naive `array.sort(() => Math.random() - 0.5)` approach produces biased distributions where some orderings are significantly more likely than others. Correct implementation: + +```typescript + +function fisherYatesShuffle(arr: T[]): T[] { + +const shuffled = [...arr]; + +for (let i = shuffled.length - 1; i > 0; i--) { + +const j = Math.floor(Math.random() * (i + 1)); + +[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; + +} + +return shuffled; + +} + +``` + +- **localStorage size limits** — localStorage has a ~5MB limit per origin. For small-to-medium decks (<500 cards), this is fine. For large decks (500+ cards) with extensive review history and progress tracking, consider using IndexedDB as a fallback. At minimum, store only essential SM-2 state per card (`{n, EF, I, due, lapses}`) — avoid storing full review logs in localStorage. +- **React hook ordering** — when implementing the spaced repetition hook, declare all React hooks (`useState`,`useRef`,`useMemo`,`useEffect`) at the top of the function before any conditional logic. Adding hooks between existing hooks during iteration (e.g., inserting a`useRef`between`useMemo` calls) will crash React's HMR during development. The order must be stable across renders. + +## Limitations + +- Cannot read existing `.apkg` files (genanki is write-only); cannot sync to AnkiWeb +- Cannot track review history across sessions unless building a persistent app (use localStorage or IndexedDB for client-side persistence) + +- Verify generated content for specialized domains — confident-sounding wrong cards are worse than no cards diff --git a/.local/secondary_skills/geo/.fingerprint b/.local/secondary_skills/geo/.fingerprint new file mode 100644 index 0000000..2ddc993 --- /dev/null +++ b/.local/secondary_skills/geo/.fingerprint @@ -0,0 +1 @@ +0760d9e0fc0d670fdb9d1faad240bbb5 \ No newline at end of file diff --git a/.local/secondary_skills/geo/SKILL.md b/.local/secondary_skills/geo/SKILL.md new file mode 100644 index 0000000..28127f4 --- /dev/null +++ b/.local/secondary_skills/geo/SKILL.md @@ -0,0 +1,378 @@ +--- +name: geo +description: Optimize content for AI-generated answers in ChatGPT, Perplexity, and Google AI Overviews. +--- + +# Generative Engine Optimization (GEO) + +Optimize web content so it gets cited, quoted, and surfaced by AI engines (ChatGPT, Google AI Overviews/SGE, Perplexity, Bing Copilot, Claude, and others). GEO differs from traditional SEO because AI engines don't rank pages — they synthesize answers from sources. The goal is to become one of those sources. + +## When to Use + +- User asks to optimize content for AI search or AI engines +- User wants to audit or rewrite existing pages/posts for GEO readiness + +- User wants to create new content designed to appear in AI-generated answers +- User wants a GEO content strategy or roadmap for their brand/blog + +- User mentions GEO, generative engine optimization, or AI visibility +- User asks how to get cited by ChatGPT, Perplexity, Google AI Overviews, etc. + +## Research Foundation + +Key research finding (Princeton/IIT Delhi, KDD 2024): The most impactful GEO signals are **statistics (+33.9% visibility)**, **expert quotes (+32%)**, **fluent writing (+30%)**, and **authoritative citations (+30.3%)**. These numbers should guide prioritization — when time is limited, adding statistics and expert quotes yields the highest return. + +## How AI Engines Select Sources + +AI engines decide what to cite based on several signals. Every recommendation in this skill traces back to one of them: + +1. **Direct answerability** — Content that directly answers a question in a clear, self-contained way is more likely to be extracted. AI engines prefer content that doesn't require inference to understand. +2. **Authority signals** — Cited statistics, named sources, references to studies, and expert attribution increase trust. AI engines weight sourced claims higher than unsourced opinions. + +3. **Structured clarity** — Well-organized content with clear headings, lists, and logical flow is easier for models to parse and quote. 74% of AI citations come from structured lists and comparison formats. +4. **Topical depth** — Content that covers a topic comprehensively with specifics (numbers, examples, comparisons) is preferred over shallow overviews. + +5. **Freshness and accuracy** — Up-to-date content with current data points wins over stale pages. Contradicting widely-known facts gets filtered out. +6. **Technical accessibility** — Proper schema markup, fast load times, and clean HTML help crawlers index content correctly. + +7. **Community signals** — Reddit, LinkedIn, Quora, and forum mentions are crawled by AI engines. Content that generates authentic discussion in these communities gets additional visibility. + +## Three Modes + +### Mode 1: Audit & Rewrite Existing Content + +When the user provides existing content (URL, blog post, article, page) to evaluate or improve. + +#### Process + +1. **Collect the content** — Get the URL or raw content from the user. If it's a URL, fetch and extract the main content body. +2. **Identify the core query** — What search or AI prompt is this content answering? What would someone type into ChatGPT to find this? + +3. **Evaluate against the GEO scorecard** (see `scorecard.md` for the full checklist). +4. **Apply the rewrite checklist** if the user wants improvements (not just an audit): + +- Add a direct answer block in the first 40-60 words — open with the key phrase ("X is..." or "The best Y for Z is..."). This is the single highest-impact change. +- Inject statistics — at least one concrete data point per major section. Flag where data is needed if none is available. + +- Add or strengthen named expert quotes — direct attribution to a real person or study. +- Add source citations inline — link to research, .gov, .edu, or recognized publications. + +- Rewrite H2/H3 headings as questions or clear topical answers ("How does X work?" not "Overview"). +- Add or expand a FAQ section — 5-10 questions in real user language at the end. + +- Improve information density — named entities, stats, and specific claims per paragraph (not vague generalities). +- Clearly name the brand/author early in the post and in the byline. + +- Trim marketing fluff — remove filler phrases that add length without adding facts ("In today's fast-paced world...", "It's important to note..."). +- Add Article JSON-LD schema (see `technical-checklist.md`) if the user manages their own site. + +1. **Produce the audit report** using the format below. + +#### Audit Report Format + +```markdown + +# GEO Audit Report: [Page Title or URL] + +## Overall GEO Readiness: [Score]/100 + +## Summary + +[2-3 sentence overview of the page's GEO strengths and weaknesses] + +## Scores by Category + +| Category | Score | Status | + +|----------|-------|--------| + +| Direct Answerability | X/20 | [needs work / good / strong] | + +| Authority & Citations | X/20 | [needs work / good / strong] | + +| Structure & Formatting | X/20 | [needs work / good / strong] | + +| Topical Depth | X/20 | [needs work / good / strong] | + +| Technical Optimization | X/20 | [needs work / good / strong] | + +## Detailed Findings + +### Direct Answerability + +[What's working, what's missing, specific examples from the content] + +### Authority & Citations + +[Assessment of sourcing, statistics, expert quotes, credibility signals] + +### Structure & Formatting + +[Heading hierarchy, use of lists, paragraph length, scanability] + +### Topical Depth + +[Coverage completeness, specificity, comparisons, examples provided] + +### Technical Optimization + +[Schema markup, meta data, page speed considerations, HTML cleanliness] + +## Priority Recommendations + +1. [Highest-impact change with specific instructions] +2. [Second priority] + +3. [Third priority] + +... + +## Rewritten Sections (if requested) + +[Full rewritten content, followed by a "GEO changes made" summary] + +``` + +#### Delivering the Report as PDF + +After writing the audit report as a markdown file, convert it to PDF and present it to the user. + +1. Write the audit report to a `.md` file (e.g., `.local/geo-audit-[site-name].md`). +2. Convert the markdown to a styled PDF (use available workspace tools or libraries such as `pdfkit`). +3. Present the PDF to the user using the file presentation tool. + +### Mode 2: Create GEO-Optimized Content + +When the user wants to write new content from scratch. + +#### Pre-Writing — Confirm These First (ask if not provided) + +- **Target query / topic** — What question is this content answering? +- **Target audience** — Who is reading this? + +- **Content type** — Blog post, product page, FAQ, documentation, landing page, comparison page? +- **Brand voice/tone** — Formal, conversational, technical? + +- **Approximate length** — Default: 1,200-2,000 words for blog posts/articles. + +#### GEO-Native Blog Post Structure + +```text + +[TITLE — phrased as a question or definitive answer] + +e.g. "What Is X? The Complete Guide" or "How to Do Y in 2026" + +[BYLINE — Author name + credentials/title] + +[DATE — always include publish date] + +[DIRECT ANSWER BLOCK — 40-60 words] + +Immediately answers the post's core question. No preamble. + +Starts with the key phrase: "X is..." or "The best way to Y is..." + +[KEY STATISTICS — 2-3 bullet data points] + +Fast-load authority signals AI engines extract immediately. + +[H2: Why Does X Matter? / What Is X?] + +Dense, factual prose. Named sources. Specific claims. + +[H2: How Does X Work? — or next logical question] + +Same pattern. Include at least one expert quote or study citation. + +[H2: Ranked List or Comparison Table] + +"Top 5 ways to..." or "X vs Y" — structured lists are highly citable. + +[H2: Common Questions About X] + +5-10 FAQ entries in real user language. + +Q: [exact phrasing someone would type into ChatGPT] + +A: [self-contained 2-3 sentence answer — extractable on its own] + +[SOURCES / REFERENCES] + +Numbered list of all cited sources with URLs. + +``` + +For other content types (product pages, documentation, landing pages, comparison pages), read `content-patterns.md` for type-specific templates. + +#### Creation Process + +1. **Research the query landscape** — Identify the questions users and AI engines ask about this topic. Think about what an AI engine would need to construct a complete answer. +2. **Plan the content structure** — Use the blog post template above or the appropriate pattern from `content-patterns.md`. + +3. **Write with GEO principles applied** throughout (see Writing Rules below). +4. **Add technical optimization** — Schema markup recommendations, meta descriptions, etc. + +### Mode 3: GEO Content Strategy + +When the user wants a strategic GEO roadmap for their blog, brand, or website. + +#### Process (2) + +##### Step 1: Define the entity + +- What is the brand/person/product being optimized? +- What are the 3-5 core topics they want to be cited for? + +- Who are the target audiences? + +###### Step 2: Identify target prompts + +Generate 15-25 specific prompts the target audience would type into ChatGPT, Perplexity, or Google AI Overviews — these are the GEO equivalent of keywords. Focus on: + +- Informational: "What is the best [topic] for [use case]?" +- How-to: "How do I [task related to the niche]?" + +- Comparative: "X vs Y: which is better for Z?" +- Definitional: "What is [core concept]?" + +###### Step 3: Content gap analysis + +For each target prompt, assess: + +- Does existing content answer it directly? +- What content format would AI engines prefer? (FAQ, article, comparison, listicle) + +- What authority signals are missing? + +###### Step 4: Prioritized content plan + +Produce a prioritized list of content pieces to create or optimize, ranked by: + +- **Citation potential** — How likely is an AI engine to pull from this format? +- **Competitive gap** — Is this topic underserved by competitors? + +- **Business impact** — Does citation here drive leads, revenue, or brand awareness? + +###### Step 5: Platform-specific tactics + +Read `platform-notes.md` for engine-specific recommendations. + +###### Step 6: Measurement framework + +Recommend the user track: + +- **Mention rate** — % of target prompts that return the brand name (test manually or via tools like Profound, Otterly.ai) +- **Citation rate** — % that include a clickable URL to their domain + +- **Citation position** — First mention vs. buried in the response +- **Review cadence** — Monthly minimum; weekly for active campaigns + +## Writing Rules + +These apply across all modes — as requirements when creating, as recommendations when auditing: + +### Answer-First Structure + +Place the direct answer in the first 40-60 words of the relevant section. AI engines extract opening statements more frequently than buried conclusions. Don't build up to the answer — lead with it, then support it. This is the single highest-impact optimization. + +### Quotable Statements + +Write sentences that work as standalone quotes. AI engines pull individual sentences or short paragraphs. Each key claim should be a self-contained, factual statement that makes sense without surrounding context. + +- Good: "The average cost of a kitchen renovation in 2025 ranges from $15,000 to $45,000, depending on scope, materials, and geographic location." +- Bad: "When thinking about costs, there are many factors to consider, and it really depends on what you're looking for." + +### Facts Over Opinions + +Every claim gets a source. Include specific numbers, percentages, study names, expert names, and publication references. Unsourced claims are treated as opinions by AI engines. Even when writing original analysis, anchor claims to verifiable data points. Flag where data is needed if it's unavailable — don't leave unsourced assertions. + +### Use Structured Formats + +- **Definition blocks** — "X is [clear definition]" format for definitional queries +- **Step-by-step lists** — Numbered steps for how-to queries + +- **Comparison tables** — Side-by-side comparisons for "vs" or "best" queries +- **FAQ sections** — Question-and-answer pairs using actual user questions + +- **Pros/cons lists** — For evaluation queries + +### Heading Hierarchy as Query Map + +Each H2/H3 should mirror a natural question someone would ask. AI engines use headings to locate relevant sections. "How Much Does X Cost?" is better than "Pricing Information" because it matches the query pattern. + +### Comprehensive Coverage + +Cover the topic from multiple angles. AI engines prefer sources that address the full scope of a query — including related questions, edge cases, and common follow-ups. Thin content that only partially answers a question gets passed over for more complete sources. + +### Freshness Signals + +Include dates, version numbers, "as of [year]" references, and "updated on" indicators. AI engines prefer current information and will note when content appears outdated. Especially critical for Perplexity (real-time crawling) and Google AI Overviews. + +### Entity Clarity + +Name things explicitly. Instead of "the platform" or "the tool," use the actual name every time. AI engines match entities by name — pronouns and vague references break that matching. The brand/author/company should be unambiguously named and described. + +### No Filler + +Trim phrases that add length without adding facts. Remove: "In today's fast-paced world...", "It's important to note...", "As we all know...", "When it comes to...". Every sentence should contain a fact, a specific claim, or a direct answer. + +### Paragraph Discipline + +Keep paragraphs to 3-5 sentences maximum. Dense walls of text get skipped by both AI engines and human readers. + +## Universal Principles + +- **GEO and SEO compound.** Content that ranks well on Google is more likely to be in AI training data. Optimize for both. +- **Community signals count.** Reddit, LinkedIn, Quora, and forum mentions are crawled by AI engines. Encourage authentic discussion around your content. + +- **Write for humans first.** AI clarity follows from human clarity — if it reads well to a person, it parses well for an AI engine. + +## Content Patterns by Type + +Read `content-patterns.md` for detailed templates and examples for each content type: + +- Blog posts and articles +- Product and service pages + +- FAQ and knowledge base pages +- Technical documentation + +- Landing pages +- Comparison and review pages + +## Technical Optimization Checklist + +Read `technical-checklist.md` for: + +- Schema markup (JSON-LD) recommendations by content type +- Meta description optimization for AI extraction + +- HTML semantics best practices +- Page performance considerations + +- Sitemap and crawlability + +## Platform-Specific Considerations + +Different AI engines have different behaviors. Read `platform-notes.md` for engine-specific guidance: + +- **ChatGPT/OpenAI** — Browsing plugin and training data considerations +- **Google AI Overviews** — Integration with traditional search signals + +- **Perplexity** — Real-time crawling and citation patterns +- **Bing Copilot** — Bing index reliance and citation style + +## Common Mistakes + +- **Keyword stuffing** — AI engines parse semantics, not keyword density. Unnatural repetition hurts readability without improving AI visibility. +- **Thin content** — Short pages that only scratch the surface lose to comprehensive competitors. Depth wins. + +- **Missing attribution** — Claims without sources are treated as opinions. Always cite. +- **Poor structure** — Wall-of-text content is hard for AI to parse and quote. Use headings, lists, and short paragraphs. + +- **Ignoring related queries** — Answering only the primary question misses opportunities. Cover the "People Also Ask" and follow-up questions. +- **Outdated information** — AI engines deprioritize stale content. Keep data points and references current. + +- **Burying the answer** — Leading with background or preamble instead of the direct answer. The answer belongs in the first 40-60 words. +- **Vague language** — Generic statements ("many experts agree", "studies show") without naming the experts or studies. AI engines can't cite what isn't specific. diff --git a/.local/secondary_skills/geo/references/content-patterns.md b/.local/secondary_skills/geo/references/content-patterns.md new file mode 100644 index 0000000..bc28e87 --- /dev/null +++ b/.local/secondary_skills/geo/references/content-patterns.md @@ -0,0 +1,158 @@ +# GEO Content Patterns by Type + +Templates and structural patterns for creating GEO-optimized content across different content types. + +## Blog Posts and Articles + +### Structure + +1. **Opening paragraph** — State the core answer/thesis in the first 2 sentences. Include a key statistic if available. +2. **Table of contents** — For posts over 1000 words, include a linked TOC. AI engines use these to understand topic scope. + +3. **Core sections** (H2s) — Each H2 should be a question or a clear topic phrase. Lead each section with its answer. +4. **Supporting detail** — After the direct answer, provide context, examples, data, and nuance. + +5. **FAQ section** — End with 3-5 frequently asked questions in Q&A format. These are highly extractable by AI engines. +6. **Summary/Key takeaways** — Bullet list of the main points. AI engines frequently pull from summary sections. + +### Example Opening + +```text + +## How Long Does It Take to Learn Python? + +Most beginners can learn Python basics in 2-4 weeks with consistent daily practice of 1-2 hours. + +Reaching intermediate proficiency typically takes 3-6 months, while advanced mastery requires + +1-2 years of hands-on project experience. According to a 2024 Stack Overflow survey, Python + +remains the most-wanted programming language, with 67% of developers who don't use it expressing + +interest in learning it. + +``` + +## Product and Service Pages + +### Structure (2) + +1. **Product definition** — "X is a [category] that [primary function] for [target audience]." +2. **Key features/benefits** — Bulleted list with one-line descriptions. + +3. **How it works** — Numbered steps or brief process explanation. +4. **Pricing** (if applicable) — Clear pricing table or range. AI engines frequently cite pricing info. + +5. **Comparison to alternatives** — Brief positioning against known competitors or categories. +6. **Use cases** — 2-3 specific scenarios with concrete details. + +7. **FAQ** — Common purchase/usage questions answered directly. + +### Key Principle + +Product pages often get skipped by AI engines because they read as marketing copy. Counter this by including factual, verifiable claims, specific numbers (dimensions, speeds, capacities), and honest comparisons. AI engines trust product pages that read like informed reviews more than ones that read like ads. + +## FAQ and Knowledge Base Pages + +### Structure (3) + +- Each question as an H2 or H3 +- Answer in the first sentence, explanation following + +- Use the exact phrasing people use when asking (natural language, not jargon) +- Group related questions under topic headings + +- Include "Related questions" links between entries + +### Example + +```text + +## Can I return an opened product? + +Yes, opened products can be returned within 30 days of purchase for a full refund, provided + +they are in resalable condition with original packaging. Exceptions include perishable goods, + +personalized items, and digital downloads. To initiate a return, contact support@example.com + +or use the Returns portal in your account dashboard. + +``` + +### Key Principle (2) + +FAQ pages are the highest-value GEO content type because they directly match question-answer patterns. Each Q&A pair is a self-contained unit that AI engines can extract whole. Write each answer as if it will be read without any surrounding context. + +## Technical Documentation + +### Structure (4) + +1. **Overview** — What the tool/API/feature does in 1-2 sentences. +2. **Quick start** — Minimal steps to get running. + +3. **Detailed usage** — Organized by feature or use case. +4. **Code examples** — Annotated, runnable code snippets. + +5. **Configuration reference** — Tables of parameters, options, defaults. +6. **Troubleshooting** — Common errors and their solutions. + +7. **Changelog/Version notes** — What changed and when. + +### Key Principle (3) + +Technical docs get cited heavily by AI coding assistants. Make code examples copy-pasteable and self-contained. Include expected output. Use consistent parameter tables with columns: Name, Type, Default, Description. Date version references clearly. + +## Landing Pages + +### Structure (5) + +1. **Hero statement** — Clear value proposition in one sentence. +2. **Problem/solution framing** — What problem you solve, stated concretely. + +3. **Social proof** — Named testimonials, client logos, specific metrics ("used by 10,000+ teams"). +4. **Feature highlights** — 3-5 key features with specific benefits. + +5. **How it works** — Simple 3-step explanation. +6. **Pricing/CTA** — Clear next step. + +### Key Principle (4) + +Landing pages are harder to optimize for GEO because they are inherently promotional. Include enough factual, verifiable information (founding year, team size, concrete metrics, named clients) that AI engines can treat the page as a source of facts rather than just marketing. + +## Comparison and Review Pages + +### Structure (6) + +1. **Verdict up front** — State the recommendation in the opening. +2. **Comparison table** — Side-by-side feature/price/spec comparison. + +3. **Category-by-category analysis** — Each criterion as its own section with a clear winner stated. +4. **Use-case recommendations** — "Best for X: [Option A]. Best for Y: [Option B]." + +5. **Methodology** — Brief note on how you evaluated. +6. **FAQ** — Common decision-making questions. + +### Key Principle (5) + +Comparison queries ("X vs Y", "best Z for W") are among the most common AI engine queries. AI engines love structured comparison content because it directly answers decision-making questions. Use tables generously. State clear opinions backed by specific criteria — AI engines cite decisive analysis, not fence-sitting. + +### Example Comparison Table + +```markdown + +| Feature | Tool A | Tool B | Tool C | + +|---------|--------|--------|--------| + +| Starting Price | $12/mo | $29/mo | Free | + +| Max Users | 10 | Unlimited | 5 | + +| API Access | Yes | Yes | No | + +| Mobile App | iOS only | iOS + Android | iOS + Android | + +| Best For | Small teams | Enterprise | Solo users | + +``` diff --git a/.local/secondary_skills/geo/references/platform-notes.md b/.local/secondary_skills/geo/references/platform-notes.md new file mode 100644 index 0000000..823be94 --- /dev/null +++ b/.local/secondary_skills/geo/references/platform-notes.md @@ -0,0 +1,128 @@ +# Platform-Specific GEO Notes + +Each AI engine has different crawling, indexing, and citation behaviors. These notes help tailor optimization strategy by platform. + +## ChatGPT / OpenAI + +**Crawler:** `GPTBot` + +**How it finds content:** + +- Training data (periodic, large-scale ingestion) +- Browsing tool (real-time web search when users ask current questions) + +- When browsing, ChatGPT uses Bing's search index as a starting point, then fetches and reads pages directly + +**Citation behavior:** + +- Provides inline citations with links when using the browsing tool +- For training data responses, sources are not cited — the model synthesizes from memory + +- Tends to cite authoritative domains and well-structured content +- Prefers content that provides clear, definitive answers over hedged language + +**Optimization priorities:** + +1. Ensure GPTBot is not blocked in robots.txt +2. Focus on comprehensive, well-sourced content (training data quality) + +3. Strong meta descriptions and opening paragraphs (browsing tool extraction) +4. FAQ-style content works well for direct question matching + +## Google AI Overviews (formerly SGE) + +**Crawler:** Standard `Googlebot` (plus `Google-Extended` for training) + +**How it finds content:** + +- Uses Google's existing search index as the primary source +- AI Overviews appear above traditional search results for eligible queries + +- Traditional SEO signals (backlinks, domain authority, PageRank) still heavily influence which sources get cited in AI Overviews + +**Citation behavior:** + +- Shows source cards alongside the AI-generated answer +- Typically cites 2-5 sources per overview + +- Strongly favors pages that already rank in the top 10 for the query +- Uses structured data to enhance source cards (images, site name, breadcrumbs) + +**Optimization priorities:** + +1. Traditional SEO still matters heavily — domain authority, backlinks, and ranking position directly influence AI Overview citation +2. Schema markup is more impactful here than other platforms because Google uses it to render rich source cards + +3. Content that matches Google's E-E-A-T guidelines (Experience, Expertise, Authoritativeness, Trustworthiness) gets preferential citation +4. Heading-question alignment is critical — Google matches AI Overview sub-answers to page sections via headings + +## Perplexity AI + +**Crawler:** `PerplexityBot` + +**How it finds content:** + +- Real-time web crawling for every query (always fetches fresh content) +- Indexes and caches frequently-cited sources + +- Also uses its own search index built from ongoing crawling + +**Citation behavior:** + +- Heavy citation model — almost every claim gets a numbered source reference +- Cites the specific page (and sometimes section) that supports each claim + +- Prefers pages with clear, verifiable, specific information +- Will cite multiple sources in a single answer, often 5-10+ + +**Optimization priorities:** + +1. Freshness is critical — Perplexity crawls in real-time, so up-to-date content wins +2. Ensure PerplexityBot is not blocked in robots.txt + +3. Specific, quotable statements with data points are highly cited +4. Page load speed matters — Perplexity has crawl timeouts + +5. Content that covers niche sub-topics well gets cited for those specific sub-queries + +## Bing Copilot + +**Crawler:** Standard `Bingbot` + +**How it finds content:** + +- Uses Bing's search index +- Real-time search + AI synthesis for each query + +- Microsoft's AI integration means Copilot answers appear across Bing, Edge, Windows, and Microsoft 365 + +**Citation behavior:** + +- Inline numbered citations linking to source pages +- Typically cites 3-6 sources per answer + +- Bing's index favors well-structured, authoritative content +- Social signals and freshness can influence Bing ranking more than Google + +**Optimization priorities:** + +1. Submit site to Bing Webmaster Tools (separate from Google Search Console) +2. Bing places slightly more weight on social signals and exact-match content + +3. Strong semantic HTML structure helps Bing's parser +4. Clear authorship signals and organization info boost authority + +5. IndexNow protocol support can speed up Bing indexing of new/updated content + +## Cross-Platform Strategy + +Given that each platform has different strengths, a good cross-platform approach: + +1. **Don't block any AI crawlers** in robots.txt unless you have a specific reason +2. **Maintain strong traditional SEO** — it directly feeds Google AI Overviews and influences Bing Copilot + +3. **Keep content fresh** — critical for Perplexity, helpful for all +4. **Use schema markup** — highest impact on Google, but helps all platforms + +5. **Write quotable, self-contained statements** — this is the single most impactful practice across all AI engines +6. **Submit to both Google Search Console and Bing Webmaster Tools** — covers the two major search indexes that AI engines rely on diff --git a/.local/secondary_skills/geo/references/scorecard.md b/.local/secondary_skills/geo/references/scorecard.md new file mode 100644 index 0000000..11c1d5a --- /dev/null +++ b/.local/secondary_skills/geo/references/scorecard.md @@ -0,0 +1,113 @@ +# GEO Audit Scorecard + +Use this checklist when evaluating existing content. Each category is scored out of 20 points for a total of 100. + +## 1. Direct Answerability (20 points) + +| Criterion | Points | What to Look For | + +|-----------|--------|------------------| + +| Lead with the answer | 5 | Does the content answer the primary query in the first 1-2 sentences of the relevant section? | + +| Quotable sentences | 5 | Are there self-contained, factual sentences that work as standalone quotes? Count how many key claims pass the "copy-paste into an AI answer" test. | + +| Query-intent match | 5 | Does the content match what someone actually searching this topic wants to know? (informational, transactional, navigational) | + +| Concise definitions | 5 | For definitional topics, is there a clear "X is..." statement? For how-to topics, are steps numbered and actionable? | + +### Scoring Guide + +- 0-5: Content buries answers, requires heavy inference +- 6-10: Some direct answers but inconsistent + +- 11-15: Most key questions answered directly +- 16-20: Every section leads with its answer, highly extractable + +## 2. Authority & Citations (20 points) + +| Criterion | Points | What to Look For | + +|-----------|--------|------------------| + +| Statistics and data | 5 | Are specific numbers, percentages, and data points included? Are they sourced? | + +| Expert attribution | 5 | Are claims attributed to named experts, organizations, or studies? | + +| Source diversity | 5 | Do citations come from multiple credible sources (not just one)? | + +| Recency of sources | 5 | Are cited data points and studies current (within 1-2 years for fast-moving topics)? | + +### Scoring Guide (2) + +- 0-5: No sources, all opinion +- 6-10: Some statistics but mostly unsourced + +- 11-15: Good sourcing with minor gaps +- 16-20: Comprehensive, well-sourced, diverse citations throughout + +## 3. Structure & Formatting (20 points) + +| Criterion | Points | What to Look For | + +|-----------|--------|------------------| + +| Heading hierarchy | 5 | Clear H1 > H2 > H3 progression? Do headings mirror natural queries? | + +| List and table usage | 5 | Are comparison data, steps, and options formatted as lists or tables instead of prose? | + +| Paragraph length | 5 | Are paragraphs 2-4 sentences? No walls of text? | + +| Scanability | 5 | Can someone (or an AI) find the answer to a specific sub-question by scanning headings alone? | + +### Scoring Guide (3) + +- 0-5: Wall of text, no clear structure +- 6-10: Basic structure but inconsistent formatting + +- 11-15: Good structure with clear sections +- 16-20: Excellent hierarchy, every section is scannable and parseable + +## 4. Topical Depth (20 points) + +| Criterion | Points | What to Look For | + +|-----------|--------|------------------| + +| Coverage breadth | 5 | Does the content address the full scope of the topic, including related questions? | + +| Specificity | 5 | Are there concrete examples, case studies, specific numbers instead of generalities? | + +| Edge cases and nuance | 5 | Does the content address exceptions, caveats, and "it depends" scenarios? | + +| Follow-up anticipation | 5 | Does the content proactively answer likely follow-up questions? | + +### Scoring Guide (4) + +- 0-5: Surface-level, could be written without expertise +- 6-10: Covers basics but lacks depth + +- 11-15: Solid coverage with good specifics +- 16-20: Comprehensive, expert-level depth with nuance + +## 5. Technical Optimization (20 points) + +| Criterion | Points | What to Look For | + +|-----------|--------|------------------| + +| Schema markup | 5 | Appropriate JSON-LD present (Article, FAQ, HowTo, Product, etc.)? | + +| Meta description | 5 | Meta description is a clear, concise answer to the primary query? Under 160 chars? | + +| Semantic HTML | 5 | Proper use of article, section, header, nav, main tags? Clean heading hierarchy in HTML? | + +| Page performance | 5 | Fast load time? No excessive scripts blocking content? Mobile-friendly? | + +### Scoring Guide (5) + +- 0-5: No technical optimization +- 6-10: Basic meta tags but no schema or poor HTML + +- 11-15: Good technical foundation with minor gaps +- 16-20: Full schema markup, optimized meta, clean HTML, fast loading diff --git a/.local/secondary_skills/geo/references/technical-checklist.md b/.local/secondary_skills/geo/references/technical-checklist.md new file mode 100644 index 0000000..05313df --- /dev/null +++ b/.local/secondary_skills/geo/references/technical-checklist.md @@ -0,0 +1,257 @@ +# GEO Technical Optimization Checklist + +Technical optimizations that help AI engines discover, parse, and cite your content. + +## Schema Markup (JSON-LD) + +Schema markup helps AI engines understand content type and structure. Use JSON-LD format in the `` or end of ``. + +### By Content Type + +**Article / Blog Post:** + +```json + +{ + +"@context": "https://schema.org", + +"@type": "Article", + +"headline": "How to Choose the Right CRM for Your Business", + +"author": { + +"@type": "Person", + +"name": "Jane Smith", + +"jobTitle": "CRM Consultant", + +"url": "https://example.com/about/jane-smith" + +}, + +"datePublished": "2025-01-15", + +"dateModified": "2025-03-20", + +"publisher": { + +"@type": "Organization", + +"name": "Example Inc." + +}, + +"description": "A comprehensive guide to selecting the right CRM system based on team size, budget, and use case." + +} + +``` + +**FAQ Page:** + +```json + +{ + +"@context": "https://schema.org", + +"@type": "FAQPage", + +"mainEntity": [ + +{ + +"@type": "Question", + +"name": "How much does a CRM cost?", + +"acceptedAnswer": { + +"@type": "Answer", + +"text": "CRM pricing ranges from free for basic tools to $300+/user/month for enterprise solutions. Most small businesses spend $12-$50/user/month." + +} + +} + +] + +} + +``` + +**HowTo (step-by-step guides):** + +```json + +{ + +"@context": "https://schema.org", + +"@type": "HowTo", + +"name": "How to Set Up a CRM in 5 Steps", + +"step": [ + +{ + +"@type": "HowToStep", + +"name": "Define your requirements", + +"text": "List the features your team needs: contact management, pipeline tracking, email integration, reporting." + +} + +] + +} + +``` + +**Product Page:** + +```json + +{ + +"@context": "https://schema.org", + +"@type": "Product", + +"name": "ProductName Pro", + +"description": "...", + +"offers": { + +"@type": "Offer", + +"price": "29.99", + +"priceCurrency": "USD" + +}, + +"aggregateRating": { + +"@type": "AggregateRating", + +"ratingValue": "4.7", + +"reviewCount": "1250" + +} + +} + +``` + +**Organization (site-wide, placed on homepage):** + +```json + +{ + +"@context": "https://schema.org", + +"@type": "Organization", + +"name": "Example Inc.", + +"url": "https://example.com", + +"foundingDate": "2018", + +"description": "...", + +"sameAs": [ + +"https://twitter.com/example", + +"https://linkedin.com/company/example" + +] + +} + +``` + +## Meta Description Optimization + +AI engines sometimes use meta descriptions as quick summaries. Optimize them for extraction: + +- Write the meta description as a direct answer to the primary query the page targets +- Keep under 155-160 characters + +- Include one key data point or specific claim +- Avoid generic marketing language + +**Good:** `"Kitchen renovations cost $15,000-$45,000 on average in 2025. Scope, materials, and location are the biggest cost factors."` + +**Bad:** `"Learn everything you need to know about kitchen renovations. Click to read more!"` + +## Semantic HTML + +Clean HTML structure helps crawlers parse content accurately: + +- Use `
` for the main content body +- Use `
` to group thematic content blocks + +- Use `
`, `