Communitygithub.com

Análise de Demanda de Issues do GitHub

Analisa issues abertas de um repositório público de um concorrente via API REST do GitHub, filtra ruídos localmente, agrupa em 6 categorias de demanda, calcula pontuação por issue e cluster, e gera um relatório ranqueado de lacunas de demanda com um briefing de mensagens de Go-to-Market (GTM).

O que é Análise de Demanda de Issues do GitHub?

Esta skill é projetada para extrair sinais de demanda do usuário a partir de issues abertas de repositórios públicos de concorrentes no GitHub. Ela utiliza a API REST do GitHub para buscar até 200 issues, aplica uma filtragem local rigorosa para remover ruídos como issues de bots, pull requests e itens com zero engajamento, resultando em um conjunto de dados limpo e acionável. Em seguida, as issues restantes são classificadas em seis categorias de demanda predefinidas (lacuna de funcionalidade, padrão de bug, reclamação de UX, desempenho, falta de integração, falta de documentação) e agrupadas em temas de cluster. A skill calcula uma pontuação de demanda para cada issue com base em reações (principalmente +1) e comentários, priorizando sinais de compra reais sobre ruídos de discussão. O resultado final é um ranking dos clusters por pontuação total de demanda, juntamente com um briefing de mensagens GTM que inclui ângulos de posicionamento e frases de contato baseadas em títulos literais de issues, permitindo que os usuários identifiquem lacunas de funcionalidades, gerem posicionamento de produto e criem mensagens a partir de reclamações reais de usuários. A skill é acionada por comandos como "analisar issues de concorrente", "encontrar lacunas de demanda em X" ou "transformar issues do GitHub em mensagens".

Funciona com✓Claude Code~Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/Varnan-Tech/opendirectory/tree/main/skills/gh-issue-to-demand-signal

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Sinal de Demanda de Issues do GitHub

Pegue um repositório público de um concorrente. Busque suas issues abertas. Filtre ruídos localmente. Agrupe em 6 categorias de demanda. Pontue pelo engajamento real. Gere um relatório ranqueado de lacunas de demanda e um briefing de mensagens GTM.


Regra crítica: Todo título de issue na saída deve estar literalmente como veio da resposta da API do GitHub. Cada nome de tema de cluster deve ser derivado dos títulos reais de issues naquele cluster. Se sobrarem menos de 10 issues após a filtragem de ruído, pare e avise o usuário -- o repositório é pequeno demais para um agrupamento confiável. Nenhum conteúdo de issue inventado em lugar algum.


Erros Comuns

O agente vai querer...Por que isso está errado
Enviar todas as 200 issues brutas para a IA sem filtrarIssues de bots, PRs e ruídos com zero engajamento inflam as contagens dos clusters e desperdiçam contexto. Filtre localmente primeiro.
Usar o número de comentários como o principal sinal de demandaComentários incluem respostas de mantenedores, discussões fora do tópico e spam. reactions["+1"] é o sinal de comprador mais limpo.
Parafrasear títulos de issues ao resumir clustersParafrasear perde a linguagem exata do comprador, que é o objetivo central. Use títulos de issues literais.
Continuar após o Passo 4 se sobrarem menos de 10 issues após a filtragemMenos de 10 issues significa que o repositório é pequeno demais ou a URL errada foi fornecida. Agrupar dados esparsos produz categorias sem sentido.
Incluir pull requests na análiseO endpoint de Issues do GitHub também retorna PRs. Filtre verificando se a chave pull_request está ausente no objeto da issue.
Marcar uma issue como demanda ignorada sem verificar todos os 3 critériosTodos os três devem ser verdadeiros: reactions >= 10, age >= 180 dias, sem label de planejado/em andamento/roadmap. Perder um critério desqualifica a issue.

Passo 1: Verificação de Configuração

echo "GITHUB_TOKEN: ${GITHUB_TOKEN:-não definido, limite de taxa não autenticado se aplica (60 req/h)}"

Se GITHUB_TOKEN não estiver definido: Continue. Informe ao usuário: "GITHUB_TOKEN não está definido. O limite de taxa não autenticado é de 60 requisições/hora -- suficiente para 2 buscas antes de atingir o limite. Para uso repetido, adicione um token em github.com/settings/tokens (nenhuma permissão necessária para repositórios públicos)."


Passo 2: Coletar Entrada

Você precisa de:

Analise owner e repo da entrada:

python3 << 'PYEOF'
import re, sys, os

raw = "REPO_INPUT_HERE"

# Normalizar para owner/repo
if raw.startswith("http"):
    m = re.search(r"github\.com/([^/]+)/([^/?\s]+)", raw)
    if not m:
        print("ERROR: Could not parse GitHub URL. Expected format: https://github.com/owner/repo")
        sys.exit(1)
    owner, repo = m.group(1), m.group(2).rstrip("/")
elif "/" in raw:
    parts = raw.strip().split("/")
    owner, repo = parts[0], parts[1]
else:
    print("ERROR: Input must be a GitHub URL or owner/repo slug (e.g. vercel/next.js)")
    sys.exit(1)

print(f"Owner: {owner}")
print(f"Repo: {repo}")

with open("/tmp/ghd-target.txt", "w") as f:
    f.write(f"{owner}/{repo}")
PYEOF

Se a análise falhar: Pare. Pergunte: "Por favor, forneça o repositório GitHub como uma URL (https://github.com/owner/repo) ou um slug owner/repo (ex.: vercel/next.js)."


Passo 3: Buscar Issues da API REST do GitHub

Busque até 200 issues (2 páginas de 100). Verifique o limite de taxa após a primeira busca.

python3 << 'PYEOF'
import json, urllib.request, os, sys
from datetime import datetime, timezone

target = open("/tmp/ghd-target.txt").read().strip()
owner_repo = target
token = os.environ.get("GITHUB_TOKEN", "")

headers = {"Accept": "application/vnd.github+json", "User-Agent": "gh-issue-demand-signal/1.0"}
if token:
    headers["Authorization"] = f"Bearer {token}"

all_issues = []
rate_limit_hit = False

for page in [1, 2]:
    url = f"https://api.github.com/repos/{owner_repo}/issues?state=open&per_page=100&page={page}"
    req = urllib.request.Request(url, headers=headers)

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            # Verificar limite de taxa após a primeira página
            if page == 1:
                remaining = int(resp.headers.get("X-RateLimit-Remaining", 999))
                reset_ts = resp.headers.get("X-RateLimit-Reset", "")
                if remaining == 0:
                    reset_str = datetime.fromtimestamp(int(reset_ts), tz=timezone.utc).strftime("%H:%M UTC") if reset_ts else "desconhecido"
                    print(f"ERROR: GitHub rate limit exhausted. Resets at {reset_str}.")
                    print("Add GITHUB_TOKEN to your .env file to get 5000 req/hr. See github.com/settings/tokens (no scopes needed).")
                    sys.exit(1)
                print(f"Rate limit remaining: {remaining}")

                # Verificar 404/403
                status = resp.status
                if status == 404:
                    print(f"ERROR: Repo '{owner_repo}' not found. Check the URL or slug.")
                    sys.exit(1)

            page_data = json.loads(resp.read())
            if not page_data:
                print(f"Page {page}: empty, stopping.")
                break
            all_issues.extend(page_data)
            print(f"Page {page}: {len(page_data)} issues fetched")
    except urllib.error.HTTPError as e:
        if e.code == 404:
            print(f"ERROR: Repo '{owner_repo}' not found (404). Check the URL or slug.")
        elif e.code == 403:
            print(f"ERROR: Access denied (403). Repo may be private or rate limit hit.")
        else:
            print(f"ERROR: GitHub API returned HTTP {e.code}")
        sys.exit(1)
    except Exception as e:
        print(f"ERROR: Failed to fetch page {page}: {e}")
        sys.exit(1)

print(f"Total raw issues fetched: {len(all_issues)}")
json.dump(all_issues, open("/tmp/ghd-raw-issues.json", "w"), indent=2)
PYEOF

Se o GitHub retornar 404: Pare. Informe ao usuário: "Repositório não encontrado. Verifique a URL ou slug e tente novamente. Repositórios privados não são acessíveis sem autenticação e permissão explícita de repo."

Se o GitHub retornar 403 com cabeçalho de limite de taxa: Pare. Mostre o horário de redefinição e informe ao usuário para adicionar GITHUB_TOKEN.


Passo 4: Pré-Processar Localmente -- Filtrar, Pontuar, Detectar Demanda Ignorada

Nenhuma chamada de API. Python puro. Execute antes de qualquer coisa ir para a IA.

python3 << 'PYEOF'
import json, re
from datetime import datetime, timezone

raw = json.load(open("/tmp/ghd-raw-issues.json"))
target = open("/tmp/ghd-target.txt").read().strip()
now = datetime.now(tz=timezone.utc)

noise_patterns = re.compile(
    r"^(chore|deps|bump|renovate|dependabot|release|ci|build|revert)[\s:\[]",
    re.IGNORECASE
)
pr_title_patterns = re.compile(
    r"^(feat|fix|refactor|docs|test|style|perf|chore)(\(.+\))?:",
    re.IGNORECASE
)

filtered = []
noise_count = 0
noise_reasons = {}

for issue in raw:
    # Pular pull requests (o endpoint de Issues do GitHub também retorna PRs)
    if "pull_request" in issue:
        noise_count += 1
        noise_reasons["pull_request"] = noise_reasons.get("pull_request", 0) + 1
        continue

    title = issue.get("title", "")
    reactions = issue.get("reactions", {}).get("+1", 0)
    comments = issue.get("comments", 0)
    user_type = (issue.get("user") or {}).get("type", "User")

    # Pular issues criadas por bots
    if user_type == "Bot":
        noise_count += 1
        noise_reasons["bot_author"] = noise_reasons.get("bot_author", 0) + 1
        continue

    # Pular títulos com padrão de bot
    if noise_patterns.match(title):
        noise_count += 1
        noise_reasons["bot_title"] = noise_reasons.get("bot_title", 0) + 1
        continue

    # Pular títulos de PR como issue
    if pr_title_patterns.match(title):
        noise_count += 1
        noise_reasons["pr_as_issue"] = noise_reasons.get("pr_as_issue", 0) + 1
        continue

    # Pular issues com zero sinal
    if reactions == 0 and comments == 0:
        noise_count += 1
        noise_reasons["zero_signal"] = noise_reasons.get("zero_signal", 0) + 1
        continue

    # Calcular pontuação de demanda
    demand_score = (reactions * 2) + (comments * 0.5)

    # Detectar demanda ignorada
    created_at = issue.get("created_at", "")
    if created_at:
        created = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
        age_days = (now - created).days
    else:
        age_days = 0

    labels = [l.get("name", "").lower() for l in issue.get("labels", [])]
    has_planned_label = any(
        kw in label for label in labels
        for kw in ["in-progress", "planned", "roadmap", "wip", "in progress"]
    )

    ignored_demand = (
        reactions >= 10 and
        age_days >= 180 and
        not has_planned_label
    )

    filtered.append({
        "number": issue["number"],
        "title": title,
        "url": issue.get("html_url", f"https://github.com/{target}/issues/{issue['number']}"),
        "reactions_plus1": reactions,
        "comments": comments,
        "demand_score": demand_score,
        "age_days": age_days,
        "labels": labels,
        "ignored_demand": ignored_demand,
        "body_snippet": (issue.get("body") or "")[:300]
    })

# Ordenar por pontuação de demanda decrescente
filtered.sort(key=lambda x: x["demand_score"], reverse=True)

print(f"Raw issues: {len(raw)}")
print(f"Noise filtered: {noise_count} ({', '.join(f'{k}: {v}' for k, v in noise_reasons.items())})")
print(f"Issues for analysis: {len(filtered)}")

if len(filtered) < 10:
    print(f"ERROR: Only {len(filtered)} issues remain after filtering. This repo has too few engaged issues for reliable clustering.")
    print("Try a larger repo or a repo with more community engagement.")
    import sys; sys.exit(1)

# Resumo de demanda ignorada
ignored = [i for i in filtered if i["ignored_demand"]]
print(f"Ignored demand issues: {len(ignored)}")

json.dump(filtered, open("/tmp/ghd-filtered-issues.json", "w"), indent=2)
print("Pre-processing complete.")
PYEOF

Se sobrarem menos de 10 issues após a filtragem: Pare. Informe ao usuário exatamente quantas issues foram encontradas e filtradas, e por que o repositório é pequeno demais para um agrupamento de demanda confiável.


Passo 5: Agrupar Issues

Imprima as issues filtradas para análise:

python3 << 'PYEOF'
import json
filtered = json.load(open("/tmp/ghd-filtered-issues.json"))
target = open("/tmp/ghd-target.txt").read().strip()

issue_list = filtered[:150]
print(f"Repo: {target}")
print(f"Issues to cluster: {len(issue_list)}")
print()
for i in issue_list:
    labels_str = f" [{', '.join(i['labels'][:3])}]" if i['labels'] else ""
    print(f"#{i['number']} [score:{round(i['demand_score'],1)} reactions:{i['reactions_plus1']}] {i['title']}{labels_str}")
PYEOF

Classifique cada issue impressa acima em uma das seguintes 6 categorias: feature_gap, bug_pattern, ux_complaint, performance, integration_missing, docs_missing

Regras:

  • Classifique cada issue em exatamente uma categoria
  • Extraia uma declaração de dor de 1 frase usando a linguagem exata do usuário do título -- não parafraseie
  • Identifique 5-8 temas de cluster: frases curtas (3-6 palavras) capturando padrões de reclamação dominantes em todas as issues
  • Sem travessões. Sem linguagem de marketing.

Escreva sua análise em /tmp/ghd-clusters.json com esta estrutura exata:

{
  "classified_issues": [
    {"number": 123, "category": "feature_gap", "pain_statement": "Users need X which does not exist yet"}
  ],
  "cluster_themes": [
    {"theme_name": "Missing export options", "category": "feature_gap", "issue_numbers": [123, 456, 789]}
  ],
  "category_counts": {"feature_gap": 5, "bug_pattern": 3, "ux_complaint": 4, "performance": 2, "integration_missing": 6, "docs_missing": 1}
}

Após escrever o arquivo, confirme com:

python3 -c "
import json
d = json.load(open('/tmp/ghd-clusters.json'))
print(f'Classified: {len(d[\"classified_issues\"])} issues, {len(d[\"cluster_themes\"])} themes')
print('Categories:', d['category_counts'])
"

Passo 6: Briefing de Mensagens

Calcule a pontuação de demanda total por cluster e imprima os 3 principais:

python3 << 'PYEOF'
import json

filtered = json.load(open("/tmp/ghd-filtered-issues.json"))
clusters = json.load(open("/tmp/ghd-clusters.json"))
target = open("/tmp/ghd-target.txt").read().strip()

demand_by_issue = {i["number"]: i["demand_score"] for i in filtered}
issue_titles = {i["number"]: i["title"] for i in filtered}
issue_reactions = {i["number"]: i["reactions_plus1"] for i in filtered}

enriched_themes = []
for theme in clusters.get("cluster_themes", []):
    issue_nums = theme.get("issue_numbers", [])
    total_demand = sum(demand_by_issue.get(n, 0) for n in issue_nums)
    top_issues = sorted(issue_nums, key=lambda n: demand_by_issue.get(n, 0), reverse=True)[:3]
    enriched_themes.append({
        "theme_name": theme["theme_name"],
        "category": theme["category"],
        "issue_count": len(issue_nums),
        "total_demand_score": round(total_demand, 1),
        "top_issues": [
            {"number": n, "title": issue_titles.get(n, ""), "reactions": issue_reactions.get(n, 0)}
            for n in top_issues
        ]
    })

enriched_themes.sort(key=lambda x: x["total_demand_score"], reverse=True)
json.dump(enriched_themes, open("/tmp/ghd-enriched-themes.json", "w"), indent=2)

print(f"Top 3 clusters for messaging brief (repo: {target}):")
for t in enriched_themes[:3]:
    print(f"\n  {t['theme_name']} ({t['category']}) -- total demand: {t['total_demand_score']}")
    for ti in t["top_issues"]:
        print(f"    #{ti['number']}: \"{ti['title']}\" ({ti['reactions']} reactions)")
PYEOF

Gere um briefing de mensagens GTM a partir dos 3 clusters principais impressos acima.

Regras:

  • Cada ângulo de posicionamento deve citar o cluster específico de onde veio
  • Cada gancho de contato deve citar um título de issue literal entre aspas
  • Os títulos devem incluir um número ou uma dor específica nomeada -- sem declarações genéricas
  • Sem travessões. Sem palavras proibidas: poderoso, robusto, perfeito, inovador, revolucionário, simplificar, alavancar, transformar

Escreva seu briefing em /tmp/ghd-brief.json com esta estrutura exata:

{
  "repo": "owner/repo",
  "total_issues_analyzed": 120,
  "report_date": "2025-01-15T12:00:00Z",
  "messaging_brief": {
    "headline": "5 Missing Features Users Are Begging For",
    "positioning_angles": [
      {"angle": "Address the most upvoted feature gap", "source_cluster": "Missing export options", "rationale": ""}
    ],
    "outreach_hooks": [
      {"hook": "Your users keep asking: 'Support export to CSV'. We already built it.", "verbatim_issue": "Support export to CSV"}
    ]
  },
  "top_demand_clusters": []
}

Após escrever o arquivo, confirme com:

python3 -c "
import json
d = json.load(open('/tmp/ghd-brief.json'))
print(f'Brief written for {d[\"repo\"]}')
print(f'Headline: {d[\"messaging_brief\"][\"headline\"]}')
print(f'Positioning angles: {len(d[\"messaging_brief\"][\"positioning_angles\"])}')
print(f'Outreach hooks: {len(d[\"messaging_brief\"][\"outreach_hooks\"])}')
"

Passo 7: Saída Final

python3 << 'PYEOF'
import json

filtered = json.load(open("/tmp/ghd-filtered-issues.json"))
clusters = json.load(open("/tmp/ghd-clusters.json"))
enriched_themes = json.load(open("/tmp/ghd-enriched-themes.json"))
brief = json.load(open("/tmp/ghd-brief.json"))
target = open("/tmp/ghd-target.txt").read().strip()

# Ignored demand summary
ignored = [i for i in filtered if i["ignored_demand"]]

print("=" * 70)
print(f"  DEMAND GAP REPORT: {target}")
print(f"  Issues analyzed: {len(filtered)}")
print(f"  Ignored demand issues: {len(ignored)}")
print("=" * 70)

print("\n--- TOP DEMAND CLUSTERS ---")
for t in enriched_themes[:6]:
    print(f"\n  {t['theme_name']} ({t['category']})")
    print(f"  Issues: {t['issue_count']}, Total demand: {t['total_demand_score']}")
    for ti in t["top_issues"][:2]:
        print(f"    #{ti['number']}: {ti['title']}")

print("\n--- GO-TO-MARKET MESSAGING BRIEF ---")
print(f"\n  Headline: {brief['messaging_brief']['headline']}")
print("\n  Positioning Angles:")
for angle in brief['messaging_brief']['positioning_angles'][:3]:
    print(f"    - {angle['angle']} (from: {angle['source_cluster']})")
print("\n  Outreach Hooks:")
for hook in brief['messaging_brief']['outreach_hooks'][:3]:
    print(f"    - {hook['hook']}")
    print(f"      (verbatim from issue: {hook['verbatim_issue']})")

print("\n--- IGNORED DEMAND ISSUES ---")
for i in ignored[:5]:
    print(f"  #{i['number']}: {i['title']} ({i['reactions_plus1']} reactions, {i['age_days']} days old)")

print("\n" + "=" * 70)
print("  Next step: Use these insights to build features,")
print("  improve messaging, and prioritize product roadmap.")
print("=" * 70)
PYEOF

Referência de Variáveis de Ambiente

VariávelObrigatóriaDescrição
GITHUB_TOKENNão (mas recomendado)Token de acesso pessoal do GitHub para aumentar o limite de taxa de 60 req/h para 5000 req/h. Crie em github.com/settings/tokens (nenhuma permissão necessária para repositórios públicos).

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

Varnan-Tech/opendirectory

Use when the user asks to generate a blog cover image, thumbnail, or article header. Automatically uses modern typography, brand logos, and Google Search grounding to create beautiful 16:9 images with Gemini 3.1 Flash Image Preview.

Varnan-Tech/opendirectory

World-class brand strategist and naming expert. Uses an interrogation-led discovery phase to extract your brand's DNA, then applies scientific naming frameworks (Phonosemantics) and automated multi-TLD domain checking.

Varnan-Tech/opendirectory

Use when the user asks to generate or update a project's CLAUDE or AGENTS context file from a codebase scan. Writes a focused file under 100 lines containing only the non-obvious build commands, conventions, and gotchas Claude Code needs.

Varnan-Tech/opendirectory

Use when the user wants to verify cold emails, enrich a lead list, or autonomously guess email addresses from a CSV using ValidEmail.co or the open-source Reacher engine.

Varnan-Tech/opendirectory

Competitive intelligence orchestrator tracking companies across 8+ platforms (GitHub, Twitter, Reddit, HN, PH, YC Jobs) with heat scores and AI briefings.

Varnan-Tech/opendirectory

Give it your product URL or description. It finds your top 5 competitors, runs three-track PR research across all of them (editorial, podcasts, communities), identifies which channels appear most frequently, looks up the journalist or host for each, and returns a tiered outreach list with story angles and ready-to-send cold pitch drafts tailored to your product. Use when asked to find PR opportunities, discover where competitors got featured, build a media outreach list, find which journalists cover my space, or get pitch templates for press coverage.

Varnan-Tech/opendirectory

Generate high-converting, deep-dive growth case studies in MDX format. Use this skill when asked to write a case study or blog post about a company's growth, tech stack, or product-led strategy. It handles the full pipeline (researching the company via Tavily, generating a 16:9 cover image, quality checking the draft, uploading assets to cloud storage, and pushing directly to the target repository).

Varnan-Tech/opendirectory

Scans your project for outdated npm, pip, Cargo, Go, or Ruby packages. Runs a CVE security audit. Fetches changelogs, summarizes breaking changes with Gemini, and opens one PR per risk group (patch, minor, major). Includes Diagnosis Mode for install conflicts. Use when asked to update dependencies, check for outdated packages, open dependency PRs, scan for package updates, audit for CVEs, or flag breaking changes in upgrades. Trigger when a user says "check for outdated packages", "update my dependencies", "open PRs for dependency updates", "scan for CVEs", or "which packages need upgrading".

Varnan-Tech/opendirectory

Generates and updates README.md and API reference docs by reading your codebase's functions, routes, types, schemas, and architecture. Uses graphify to build a knowledge graph first, then writes accurate docs from it. Use when asked to write docs, generate a README, document an API, update stale docs, create an API reference from code, add an architecture section, or document a project in any language. Trigger when a user says their docs are missing, outdated, or wants to document their codebase without writing it manually.

Varnan-Tech/opendirectory

Evaluates expired domain candidates against a target niche, scores them by topical relevance, historical activity level, and history cleanliness, then outputs a ranked shortlist with explainable reasoning and risk flags.

Varnan-Tech/opendirectory

Brutally honest developer-experience audit for a GitHub repo. Scores 10 DX dimensions (time-to-first-success, README clarity, visual proof, install, quick-start, docs, examples, community, trust, marketing), writes a shareable roast in the requested tone (brutal/honest/kind), produces a prioritized action plan ranked by impact × effort, and sketches an ideal README. Trigger when user says "roast my repo", "audit my README", "dx audit", "developer experience review", "score my GitHub project", "before launch checklist", or "make my repo shareable".

Varnan-Tech/opendirectory

Drafts and designs a complete HTML email newsletter from a topic or content brief. Outputs paste-ready HTML for Loops, Mailchimp, Beehiiv, Resend, or any standard email platform. Includes subject line options and plain-text fallback. Trigger when a user says "write a newsletter", "draft an email newsletter", "create an HTML email", "design an email for my subscribers", or "write a newsletter about [topic]".

Varnan-Tech/opendirectory

Takes a GitHub PR URL or the current branch and writes a plain-English explanation of what it does and why, then posts it as a PR comment. Use when asked to explain a PR, summarize a pull request, write a plain-English description of a PR, add a summary comment to a PR, or understand what a PR changes. Trigger when a user says "explain this PR", "summarize this pull request", "what does this PR do", "add a comment explaining the PR", or shares a GitHub PR URL and asks what it does.

Varnan-Tech/opendirectory

Audit how often LLMs recommend your brand vs competitors and generate a GEO action plan.

Varnan-Tech/opendirectory

Find recurring confusion in your repo's GitHub Discussions, rank it by urgency, and draft the actual docs fixes and content angles — with verbatim community quotes and source links as evidence.

Varnan-Tech/opendirectory

SEO keyword research workflow for blog generation using Google Trends data. Use when writing blog posts, planning content calendars, or optimizing articles for search engines. Finds breakout keywords, builds content structure, and generates SEO-optimized blog outlines targeting tech and developer audiences.

Varnan-Tech/opendirectory

Generates a professionally designed case study PDF for B2B SaaS sales and marketing. Supports 7 page layouts, 9 style presets, 1-4 page output. Trigger when user says "create a case study", "write a customer story", "make a case study PDF", "design a success story", "turn this customer win into a PDF".

Varnan-Tech/opendirectory

Generates data visualization charts (bar, line, area, pie, doughnut, scatter, radar, treemap) as PNG using Apache ECharts v6. 1080×1080px default, 5 style presets, highlight annotations. Trigger when user says "create a chart", "visualize data", "make a bar chart", "line graph", "pie chart", "data visualization", "chart this data", "plot", "graph", or "visualize these numbers".

Varnan-Tech/opendirectory

Creates professionally designed B2B SaaS e-books in HTML + CSS, exported as print-ready PDF. 3–10 pages, 9 style presets, 11 page layout types. Trigger when user says "create an ebook", "design a lead magnet", "make a PDF guide", "build a gated content piece", "write a B2B ebook", "design a white paper", "create a nurture asset", or "make a PDF report".

Varnan-Tech/opendirectory

Fetches low-star App Store and Google Play reviews, clusters them into broken-promise patterns, and generates a ranked copy brief with positioning opportunities.

Habilidades Relacionadas