Mapeie Seu Mercado
Pegue uma descrição de produto, palavras-chave de categoria ou nomes de concorrentes. Pesquise no Reddit, HN, GitHub Issues, G2 e Google Trends por sinais reais de dor. Pontue e agrupe-os. Construa um framework de posicionamento completo: definição de ICP, temas de dor classificados com citações literais, sinais de tamanho de mercado e ângulos de mensagem derivados da linguagem real que as pessoas usam.
Regra crítica: Cada citação de dor na saída deve existir literalmente nos dados brutos coletados pelo script. Cada nome de vendedor no mapa de mercado deve vir dos resultados de raspagem do G2 ou dos resultados de pesquisa do GitHub. Tamanho de mercado deve dizer "sinais sugerem" -- nunca estime um valor em dólares a partir de proxies fracos. Se uma fonte retornar 0 resultados, reporte 0 -- não suplemente com exemplos inventados.
Erros Comuns
| O agente vai querer... | Por que isso está errado |
|---|---|
| Inventar pontos de dor ou números de tamanho de mercado | Cada citação de dor deve ser literal, dos dados brutos. Tamanho de mercado deve citar sinais encontrados. Nunca estime o tamanho de mercado "típico". |
| Pontuar pela contagem de posts em vez de pain_score | Um post com 2.000 upvotes sobre preços é mais forte do que 50 posts com 10 upvotes cada. Use a fórmula pain_score de references/pain-scoring.md. |
| Usar os mesmos subreddits para todas as categorias | r/politics adiciona ruído a uma pesquisa de devops. Detecte automaticamente subreddits relevantes a partir da categoria e nomes de concorrentes antes de pesquisar. |
| Enviar todos os sinais brutos para IA sem pontuar | Pontue localmente primeiro. Envie apenas os 60 principais sinais de alta pontuação de dor para o agrupamento de IA. Economiza tokens e melhora a qualidade do cluster. |
| Pular a extração de ICP dos metadados do post | Subreddit, flair, biografia do autor (HN) e tipo de organização no GitHub são sinais de ICP mais ricos do que o conteúdo do post. Sempre capture e reporte-os. |
| Confundir contagem de vendedores com tamanho de mercado | "47 vendedores no G2" significa competitivo, não grande. Apresente todos os sinais como indicadores direcionais, não como números exatos. |
Passo 1: Verificação de Configuração
echo "GITHUB_TOKEN: ${GITHUB_TOKEN:-não definido -- pesquisa de Issues do GitHub roda a 60 req/h não autenticado}"
echo "Nenhuma outra chave de API necessária."
echo ""
echo "Fontes de dados que serão usadas nesta execução:"
echo " Reddit JSON público (sem autenticação, 10 req/min)"
echo " HN Algolia API (sem autenticação, gratuito)"
echo " GitHub Issues API (${GITHUB_TOKEN:+autenticado, }60-5000 req/h)"
echo " Raspagem de categoria G2 (sem autenticação, análise HTML)"
echo " Google Trends (sem autenticação, endpoint não oficial)"
Se GITHUB_TOKEN não estiver definido: continue. A pesquisa não autenticada do GitHub é de 60 req/h -- o suficiente para uma execução padrão. Para uso repetido, adicione um token em github.com/settings/tokens (nenhum escopo necessário para repositórios públicos).
Passo 2: Analisar Entrada
Colete da conversa:
category-- palavra(s)-chave descrevendo o espaço de mercado (ex.: "observabilidade de desenvolvedor", "análise B2B", "ferramentas devops")competitors-- lista opcional de nomes de produtos concorrentes ou domínios (ex.: "Datadog, New Relic, Grafana")product_context-- opcional: o que o produto do usuário faz (ajuda a adaptar os ângulos de mensagem)
Se o usuário fornecer apenas uma descrição de produto sem uma palavra-chave de categoria: extraia 2-3 palavras-chave de categoria você mesmo.
Se o usuário fornecer apenas nomes de concorrentes sem categoria: infira a categoria pesquisando pelos concorrentes.
Escreva a entrada analisada:
python3 << 'PYEOF'
import json, os
data = {
"category": "CATEGORY_AQUI",
"competitors": ["COMP_1", "COMP_2"],
"product_context": "CONTEXTO_DO_PRODUTO_AQUI"
}
with open("/tmp/mym-input.json", "w") as f:
json.dump(data, f, indent=2)
print("Entrada escrita em /tmp/mym-input.json")
print(f"Categoria: {data['category']}")
print(f"Concorrentes: {', '.join(data['competitors']) if data['competitors'] else 'nenhum fornecido'}")
PYEOF
Passo 3: Executar o Script Independente de Coleta de Dados
O script lida com toda a coleta de dados. Verifique se ele existe primeiro:
ls scripts/fetch.py 2>/dev/null && echo "script disponível" || echo "não encontrado"
Se disponível, execute-o:
GITHUB_TOKEN="${GITHUB_TOKEN:-}" python3 scripts/fetch.py \
"$(python3 -c "import json; d=json.load(open('/tmp/mym-input.json')); print(d['category'])")" \
--competitors "$(python3 -c "import json; d=json.load(open('/tmp/mym-input.json')); print(','.join(d['competitors']))")" \
--context "$(python3 -c "import json; d=json.load(open('/tmp/mym-input.json')); print(d['product_context'])")" \
--output /tmp/mym-raw.json
Aguarde a conclusão (permita até 4 minutos -- pesquisas no Reddit + HN levam ~90 segundos no total).
Verifique a saída:
python3 -c "
import json
with open('/tmp/mym-raw.json') as f:
d = json.load(f)
print(f'Sinais do Reddit: {d[\"market_signals\"][\"reddit_signals_found\"]}')
print(f'Sinais do HN: {d[\"market_signals\"][\"hn_signals_found\"]}')
print(f'Sinais do GitHub: {d[\"market_signals\"][\"github_issue_signals\"]}')
print(f'Vendedores G2: {d[\"market_signals\"][\"vendor_count_g2\"]}')
print(f'Tendências: {d[\"market_signals\"][\"trends_direction\"]}')
print(f'Total de sinais: {d[\"summary\"][\"total_pain_signals\"]}')
"
Se o total de sinais for < 10: pare. Diga ao usuário: "Menos de 10 sinais de dor encontrados para esta categoria. O mercado pode ser muito nichado para cobertura do Reddit/HN, ou as palavras-chave da categoria precisam de ajuste. Tente palavras-chave mais amplas ou adicione nomes de concorrentes."
Passo 4: Agrupamento de Dor com IA
Imprima os 60 principais sinais de dor para análise de IA:
python3 -c "
import json
with open('/tmp/mym-raw.json') as f:
d = json.load(f)
top60 = sorted(d['raw_pains'], key=lambda x: x['pain_score'], reverse=True)[:60]
print(json.dumps(top60, indent=2))
"
Agora você tem os 60 principais sinais de dor. Analise-os e produza clusters de dor.
Instruções para análise de IA:
- Identifique 5-7 temas de dor recorrentes em todas as fontes
- Para cada tema: escolha um nome que use a linguagem do próprio mercado (não suas palavras)
- Agregue o pain_score de todos os sinais em cada cluster
- Selecione as 3-5 melhores citações literais para cada tema (maior pontuação, linguagem mais específica)
- Observe em quais fontes e subreddits cada tema se concentra
- Sinalize qualquer tema que apareça em apenas uma fonte (menor confiança)
Escreva os clusters em /tmp/mym-clusters.json:
{
"clusters": [
{
"theme": "linguagem exata dos dados",
"total_score": 847,
"signal_count": 34,
"sources": {"reddit": 18, "hn": 12, "github_issue": 4},
"top_subreddits": ["devops", "sysadmin"],
"verbatim_quotes": [
{"text": "citação exata", "source": "reddit", "score": 234, "url": "..."},
{"text": "citação exata", "source": "hn", "score": 87, "url": "..."}
],
"who_has_this_pain": "descrição de quem está postando sobre isso"
}
]
}
python3 -c "
import json, os
# Confirma que o arquivo de clusters foi escrito
with open('/tmp/mym-clusters.json') as f:
d = json.load(f)
print(f'Clusters escritos: {len(d[\"clusters\"])}')
for c in d['clusters']:
print(f' {c[\"theme\"]} -- score: {c[\"total_score\"]}, sinais: {c[\"signal_count\"]}')
"
Passo 5: Perfil do ICP
Imprima os sinais de ICP dos dados brutos:
python3 -c "
import json
with open('/tmp/mym-raw.json') as f:
d = json.load(f)
print('Sinais de ICP:')
print(json.dumps(d['icp_signals'], indent=2))
print()
print('Distribuição de subreddits:')
sub_counts = {}
for p in d['raw_pains']:
s = p.get('subreddit', '')
if s:
sub_counts[s] = sub_counts.get(s, 0) + 1
for sub, count in sorted(sub_counts.items(), key=lambda x: -x[1])[:10]:
print(f' r/{sub}: {count} sinais')
"
Usando os sinais de ICP e a distribuição de subreddits acima, sintetize o perfil de ICP. Escreva-o em /tmp/mym-clusters.json adicionando uma chave icp:
{
"icp": {
"who_they_are": "perfil de 2-3 frases usando linguagem dos dados",
"where_they_live": ["r/devops (89 posts)", "r/sysadmin (67 posts)", "HN ask-hn (34 threads)"],
"what_they_say": ["citação literal 1", "citação literal 2", "citação literal 3"],
"what_they_have_tried": ["ferramentas ou abordagens alternativas mencionadas nos dados"],
"confidence": "alta|média|baixa -- baseado no volume de sinais e diversidade de fontes"
}
}
Passo 6: Síntese de Tamanho de Mercado
Imprima os sinais de mercado:
python3 -c "
import json
with open('/tmp/mym-raw.json') as f:
d = json.load(f)
ms = d['market_signals']
print('Sinais de mercado:')
print(f' Vendedores G2: {ms[\"vendor_count_g2\"]}')
print(f' Direção de tendências: {ms[\"trends_direction\"]}')
print(f' Sinais HN (12m): {ms[\"hn_signals_found\"]}')
print(f' Sinais Reddit: {ms[\"reddit_signals_found\"]}')
print(f' Principais vendedores G2: {json.dumps(ms.get(\"top_vendors\", []), indent=4)}')
"
Sintetize uma avaliação direcional de tamanho de mercado usando apenas esses sinais. Não estime um valor em dólares. Use linguagem como:
- "Sinais sugerem um mercado competitivo e em crescimento" (muitos vendedores + tendências em alta)
- "Sinais sugerem um mercado inicial" (poucos vendedores + baixo volume de sinais)
- "Sinais sugerem um mercado saturado" (muitos vendedores + tendências planas/em baixa)
Adicione a avaliação a /tmp/mym-clusters.json como uma chave market_size.
Passo 7: Framework de Posicionamento
Usando os clusters (Passo 4), ICP (Passo 5) e tamanho de mercado (Passo 6), gere o framework de posicionamento.
Instruções:
- Escolha os 3 principais clusters de dor como os ângulos de posicionamento primários
- Para cada ângulo: escreva uma declaração de posicionamento usando linguagem literal dos dados (não parafraseada)
- Gere 3 títulos de landing page que usem as frases exatas que as pessoas usam nos dados de dor
- Gere 3 linhas de assunto de e-mail frio baseadas na linguagem de dor
- NÃO use palavras banidas: poderoso, robusto, integrado, inovador, revolucionário, simplificar, alavancar, transformar, revolucionar
Escreva o framework de posicionamento completo em /tmp/mym-output.json:
{
"positioning_angles": [
{
"pain": "nome do tema",
"statement": "posicionamento em uma linha usando linguagem de mercado",
"headline": "título de landing page usando linguagem literal de dor",
"cold_email_subject": "linha de assunto"
}
],
"icp_card": {
"one_liner": "uma frase: quem eles são + com o que se importam",
"where_to_find_them": [...],
"how_to_talk_to_them": "tom + notas de vocabulário dos dados"
},
"market_map": [...principais vendedores do G2 com notas de posicionamento...]
}
Passo 8: Auto-QA e Salvar Saída
Execute verificações de auto-QA:
python3 -c "
import json
# Carregar todas as saídas
with open('/tmp/mym-raw.json') as f:
raw = json.load(f)
with open('/tmp/mym-clusters.json') as f:
clusters = json.load(f)
with open('/tmp/mym-output.json') as f:
output = json.load(f)
raw_texts = set()
for p in raw['raw_pains']:
raw_texts.add(p.get('title', ''))
raw_texts.add(p.get('body_excerpt', ''))
# Verificação 1: Sem travessões
import json as j
full_text = j.dumps(output)
if '—' in full_text:
print('FALHA: travessão encontrado na saída')
else:
print('PASSOU: sem travessões')
# Verificação 2: Sem palavras banidas
banned = ['powerful', 'robust', 'seamless', 'innovative', 'game-changing',
'streamline', 'leverage', 'transform', 'revolutionize']
found = [w for w in banned if w.lower() in full_text.lower()]
if found:
print(f'FALHA: palavras banidas encontradas: {found}')
else:
print('PASSOU: sem palavras banidas')
# Verificação 3: Verificação de linguagem de tamanho de mercado
if 'billion' in full_text.lower() or 'trillion' in full_text.lower() or 'worth \$' in full_text.lower():
print('FALHA: estimativa dura de tamanho de mercado encontrada -- use apenas linguagem direcional')
else:
print('PASSOU: sem estimativas duras de tamanho de mercado')
# Verificação 4: Contagens de sinais correspondem
total = raw['summary']['total_pain_signals']
print(f'PASSOU: {total} sinais de dor totais nos dados brutos')
print('Auto-QA completo.')
"
Corrija quaisquer falhas antes de salvar.
Salve o relatório final:
python3 << 'PYEOF'
import json, re
from datetime import datetime
with open('/tmp/mym-input.json') as f:
inp = json.load(f)
with open('/tmp/mym-raw.json') as f:
raw = json.load(f)
with open('/tmp/mym-clusters.json') as f:
clusters = json.load(f)
with open('/tmp/mym-output.json') as f:
output = json.load(f)
slug = re.sub(r'[^a-z0-9]+', '-', inp['category'].lower()).strip('-')
date = datetime.now().strftime('%Y-%m-%d')
outpath_md = f"docs/market-maps/{slug}-{date}.md"
outpath_json = f"docs/market-maps/{slug}-{date}.json"
# Construir relatório em markdown
ms = raw['market_signals']
icp = clusters.get('icp', {})
market_assessment = clusters.get('market_size', {})
angles = output.get('positioning_angles', [])
icp_card = output.get('icp_card', {})
market_map = output.get('market_map', [])
lines = [
f"# Mapa de Mercado: {inp['category'].title()}",
f"Data: {date} | Sinais analisados: {raw['summary']['total_pain_signals']} | Fontes: Reddit ({ms['reddit_signals_found']}) + HN ({ms['hn_signals_found']}) + GitHub Issues ({ms['github_issue_signals']})",
"",
"---",
"",
"## Sinais de Tamanho de Mercado",
f"Vendedores no G2: {ms['vendor_count_g2']} | Google Trends: {ms['trends_direction'].upper()} | Estágio de mercado: {market_assessment.get('stage', 'veja sinais abaixo')}",
"",
market_assessment.get('summary', ''),
"",
"---",
"",
"## Seu ICP",
"",
f"**Quem eles são:** {icp.get('who_they_are', '')}",
"",
f"**Onde eles vivem:** {', '.join(icp.get('where_they_live', []))}",
"",
"**O que eles dizem:**",
]
for q in icp.get('what_they_say', []):
lines.append(f'> "{q}"')
lines += ["", "---", "", "## Principais Dores (classificadas por força do sinal)", ""]
for i, c in enumerate(clusters.get('clusters', []), 1):
lines.append(f"### Dor {i}: {c['theme']} [score: {c['total_score']}]")
sources = c.get('sources', {})
source_str = " + ".join(f"{src} ({cnt})" for src, cnt in sources.items())
lines.append(f"{c['signal_count']} sinais | Fontes: {source_str}")
lines.append(f"Quem tem essa dor: {c.get('who_has_this_pain', '')}")
lines.append("")
lines.append("Literal:")
for q in c.get('verbatim_quotes', [])[:4]:
lines.append(f"> \"{q['text']}\" (fonte: {q['source']}, score: {q['score']})")
lines.append("")
lines.append("---")
lines.append("## Posicionamento Recomendado")
lines.append("")
for a in angles:
lines.append(f"**Ângulo: {a['pain']}**")
lines.append(f"Declaração: _{a['statement']}_")
lines.append(f"Título: {a['headline']}")
lines.append(f"Assunto de e-mail: {a['cold_email_subject']}")
lines.append("")
with open(outpath_md, 'w') as f:
f.write('\n'.join(lines))
print(f"Relatório salvo em {outpath_md}")
import shutil
shutil.copy('/tmp/mym-output.json', outpath_json)
print(f"JSON salvo em {outpath_json}")
PYEOF
Conclusão
Saída gravada em:
docs/market-maps/{categoria}-{data}.md-- relatório de mercadodocs/market-maps/{categoria}-{data}.json-- dados estruturados
Resuma os achados-chave para o usuário:
- Tamanho do mercado: [Sinais sugerem...]
- ICP: [Quem eles são em 1 frase]
- Principais dores: [Cite os 3 principais clusters]
- Ângulo de posicionamento principal: [Cite o ângulo mais forte]
Aviso: Todo o texto acima é uma síntese de IA da coleta de dados reais. As citações no relatório completo são literais, não parafraseadas. Os dados crus são salvos com a saída para referência.