Merge pull request #11 from librefang/feat/hands-i18n-and-content-enhancement
feat(hands): i18n fixes, SKILL.md enhancements, and README overhaul
This commit is contained in:
28 files changed
+11693
-451
No files matched your search
@@ -1,46 +1,149 @@
|
||||
# LibreFang Registry
|
||||
|
||||
Community-maintained content registry for [LibreFang](https://github.com/librefang/librefang) -- the open-source Agent Operating System.
|
||||
Community-maintained content registry for [LibreFang](https://github.com/librefang/librefang) — the open-source Agent Operating System.
|
||||
|
||||
This repository is the single source of truth for all installable content definitions. Anyone can submit a PR to add new agents, hands, integrations, skills, or provider models -- no changes to the LibreFang binary required.
|
||||
This repository is the **single source of truth** for all installable content definitions. Anyone can submit a PR to add new agents, hands, integrations, skills, or provider models — no changes to the LibreFang binary required.
|
||||
|
||||
## Structure
|
||||
## Overview
|
||||
|
||||
| Type | Count | Description |
|
||||
|------|------:|-------------|
|
||||
| [Hands](#hands) | 14 | User-facing "apps" — agent + tools + settings + dashboard |
|
||||
| [Agents](#agents) | 32 | Autonomous agent definitions with model config and tools |
|
||||
| [Integrations](#integrations) | 25 | MCP server connections (GitHub, Slack, DBs, etc.) |
|
||||
| [Providers](#providers) | 48 | LLM provider & model metadata with pricing |
|
||||
| [Models](#providers) | 223 | Individual model definitions across all providers |
|
||||
| [Aliases](#aliases) | 70 | Short names mapped to canonical model IDs |
|
||||
| [Plugins](#plugins) | 10 | Memory, guardrails, and conversation plugins |
|
||||
| [Skills](#skills) | 2 | Reusable prompt templates and Python scripts |
|
||||
| [Workflows](#workflows) | 9 | Pre-built multi-agent workflow definitions |
|
||||
| [Templates](#templates) | 6 | Starter templates for each content type |
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
librefang-registry/
|
||||
├── agents/ # Agent definitions (TOML manifests)
|
||||
│ ├── hello-world/agent.toml
|
||||
│ ├── researcher/agent.toml
|
||||
│ └── ... (33 agents)
|
||||
├── hands/ # Hand definitions (TOML + docs)
|
||||
│ ├── browser/HAND.toml
|
||||
│ ├── trader/HAND.toml
|
||||
│ └── ... (14 hands)
|
||||
├── integrations/ # MCP server integration templates
|
||||
├── agents/ # Agent definitions (TOML manifests)
|
||||
│ ├── hello-world/
|
||||
│ │ └── agent.toml
|
||||
│ ├── researcher/
|
||||
│ │ └── agent.toml
|
||||
│ └── ... (32 agents)
|
||||
├── hands/ # Hand definitions (app bundles)
|
||||
│ ├── browser/
|
||||
│ │ ├── HAND.toml # Metadata, tools, settings, i18n (6 languages)
|
||||
│ │ └── SKILL.md # Domain expert knowledge injected at runtime
|
||||
│ ├── trader/
|
||||
│ │ ├── HAND.toml
|
||||
│ │ └── SKILL.md
|
||||
│ └── ... (14 hands)
|
||||
├── integrations/ # MCP server integration templates
|
||||
│ ├── github.toml
|
||||
│ ├── slack.toml
|
||||
│ └── ... (25 integrations)
|
||||
├── skills/ # Reusable skill definitions
|
||||
│ ├── custom-skill-prompt/skill.toml
|
||||
│ └── custom-skill-python/
|
||||
├── providers/ # LLM provider & model metadata
|
||||
│ └── ... (25 integrations)
|
||||
├── providers/ # LLM provider & model metadata
|
||||
│ ├── anthropic.toml
|
||||
│ ├── openai.toml
|
||||
│ └── ... (46 providers, 190+ models)
|
||||
├── plugins/ # Plugin packages (10 plugins)
|
||||
├── aliases.toml # Global model alias mappings
|
||||
├── schema.toml # Provider/model schema reference
|
||||
│ └── ... (48 providers, 223 models)
|
||||
├── plugins/ # Memory, guardrails, and utility plugins
|
||||
│ ├── episodic-memory/
|
||||
│ ├── guardrails/
|
||||
│ └── ... (10 plugins)
|
||||
├── skills/ # Reusable skill definitions
|
||||
│ ├── custom-skill-prompt/skill.toml
|
||||
│ └── custom-skill-python/
|
||||
├── workflows/ # Pre-built multi-agent workflow definitions
|
||||
│ ├── code-review.toml
|
||||
│ ├── research.toml
|
||||
│ └── ... (9 workflows)
|
||||
├── templates/ # Starter templates for each content type
|
||||
│ ├── agent.toml
|
||||
│ ├── HAND.toml
|
||||
│ └── ... (6 templates)
|
||||
├── docs/ # Additional documentation
|
||||
│ └── content-guide.md # Content contribution guidelines
|
||||
├── aliases.toml # Global model alias mappings (70 aliases)
|
||||
├── schema.toml # Provider/model schema reference
|
||||
├── scripts/
|
||||
│ └── validate.py # Validation script
|
||||
│ └── validate.py # Content validation script
|
||||
├── CONTRIBUTING.md
|
||||
└── LICENSE # MIT
|
||||
└── LICENSE # MIT
|
||||
```
|
||||
|
||||
## Content Types
|
||||
|
||||
### Hands
|
||||
|
||||
Hands are the **user-facing "apps"** in LibreFang. Each hand bundles an agent, tools, user-configurable settings, dashboard metrics, dependency checks, and i18n translations into a single deployable unit.
|
||||
|
||||
Every hand includes a `SKILL.md` — domain-specific expert knowledge that is injected into the agent's context at runtime, giving it deep expertise in its domain.
|
||||
|
||||
| Icon | Hand | Category | Description |
|
||||
|:----:|------|----------|-------------|
|
||||
| 📈 | analytics | data | Data collection, analysis, visualization, dashboards, and automated reporting |
|
||||
| 🔌 | apitester | development | Endpoint discovery, request validation, load testing, and regression detection |
|
||||
| 🌐 | browser | productivity | Web navigation, form filling, and multi-step web tasks with user approval |
|
||||
| 🎬 | clip | content | Turns long-form video into viral short clips with captions and thumbnails |
|
||||
| 🔍 | collector | data | Intelligence collection, change detection, and knowledge graphs |
|
||||
| 👷 | devops | development | CI/CD management, infrastructure monitoring, deployment, and incident response |
|
||||
| 📊 | lead | data | Lead generation, enrichment, scoring, and scheduled delivery |
|
||||
| 💼 | linkedin | communication | Profile optimization, content creation, networking, and engagement |
|
||||
| 🔮 | predictor | data | Signal collection, calibrated predictions, and accuracy tracking |
|
||||
| 📢 | reddit | communication | Subreddit monitoring, content posting, and engagement tracking |
|
||||
| 🧪 | researcher | productivity | Deep research, cross-referencing, fact-checking, and structured reports |
|
||||
| 🎯 | strategist | productivity | Market research, competitive analysis, and strategic planning |
|
||||
| 📈 | trader | data | Multi-signal analysis, adversarial reasoning, and risk management |
|
||||
| 𝕏 | twitter | communication | Content creation, scheduled posting, engagement, and analytics |
|
||||
|
||||
**HAND.toml format:**
|
||||
|
||||
```toml
|
||||
id = "browser"
|
||||
name = "Browser Hand"
|
||||
description = "Autonomous web browser"
|
||||
category = "productivity"
|
||||
icon = "🌐"
|
||||
tools = ["browser_navigate", "browser_click", "browser_type"]
|
||||
|
||||
[routing]
|
||||
aliases = ["browse", "open website"]
|
||||
weak_aliases = ["web", "url"]
|
||||
|
||||
[[requires]]
|
||||
key = "chromium"
|
||||
requirement_type = "binary"
|
||||
check_value = "chromium"
|
||||
|
||||
[[settings]]
|
||||
key = "headless"
|
||||
setting_type = "toggle"
|
||||
default = "true"
|
||||
|
||||
[agent]
|
||||
name = "browser-hand"
|
||||
module = "builtin:chat"
|
||||
system_prompt = """You are an autonomous web browser agent..."""
|
||||
|
||||
[dashboard]
|
||||
[[dashboard.metrics]]
|
||||
label = "Pages Visited"
|
||||
memory_key = "pages_visited"
|
||||
format = "number"
|
||||
|
||||
# i18n — 6 languages supported: zh, ja, ko, es, fr, de
|
||||
[i18n.zh]
|
||||
name = "浏览器 Hand"
|
||||
description = "自主网页浏览器"
|
||||
category = "生产力"
|
||||
|
||||
[i18n.zh.settings.headless]
|
||||
label = "无头模式"
|
||||
description = "在后台运行浏览器"
|
||||
```
|
||||
|
||||
### Agents
|
||||
|
||||
Agent definitions in `agents/<name>/agent.toml` describe autonomous agents with their model config, tools, capabilities, and routing aliases.
|
||||
Agent definitions describe autonomous agents with model configuration, tools, capabilities, and routing aliases.
|
||||
|
||||
```toml
|
||||
name = "hello-world"
|
||||
@@ -56,30 +159,11 @@ system_prompt = "You are a helpful assistant."
|
||||
tools = ["web_search", "file_read"]
|
||||
```
|
||||
|
||||
### Hands
|
||||
|
||||
Hands in `hands/<name>/HAND.toml` are higher-level application bundles -- the user-facing "apps" in LibreFang. Each hand bundles an agent config, tools, settings, dashboard metrics, and dependency requirements.
|
||||
|
||||
```toml
|
||||
id = "browser"
|
||||
name = "Browser Hand"
|
||||
category = "productivity"
|
||||
tools = ["browser_navigate", "browser_click", "browser_type"]
|
||||
|
||||
[agent]
|
||||
name = "browser-hand"
|
||||
module = "builtin:chat"
|
||||
system_prompt = "You are an autonomous web browser agent..."
|
||||
|
||||
[[settings]]
|
||||
key = "headless"
|
||||
setting_type = "toggle"
|
||||
default = "true"
|
||||
```
|
||||
**32 built-in agents:** academic-researcher, analyst, architect, assistant, code-reviewer, coder, customer-support, data-scientist, debugger, devops-lead, doc-writer, email-assistant, health-tracker, hello-world, home-automation, legal-assistant, meeting-assistant, ops, orchestrator, personal-finance, planner, recipe-assistant, recruiter, researcher, sales-assistant, security-auditor, social-media, test-engineer, translator, travel-planner, tutor, writer
|
||||
|
||||
### Integrations
|
||||
|
||||
Integration templates in `integrations/<name>.toml` define MCP server connections (GitHub, Slack, databases, etc.) with transport config, required env vars, and setup instructions.
|
||||
Integration templates define [MCP](https://modelcontextprotocol.io/) server connections with transport configuration, required environment variables, and setup instructions.
|
||||
|
||||
```toml
|
||||
id = "github"
|
||||
@@ -96,9 +180,47 @@ name = "GITHUB_PERSONAL_ACCESS_TOKEN"
|
||||
is_secret = true
|
||||
```
|
||||
|
||||
**25 integrations across 6 categories:**
|
||||
|
||||
| Category | Integrations |
|
||||
|----------|-------------|
|
||||
| DevTools | bitbucket, github, gitlab, jira, linear, sentry |
|
||||
| Data | elasticsearch, mongodb, postgresql, redis, sqlite |
|
||||
| Productivity | dropbox, gmail, google-calendar, google-drive, notion, todoist |
|
||||
| Communication | discord, slack, teams |
|
||||
| Cloud | aws, azure, gcp |
|
||||
| AI Search | brave-search, exa-search |
|
||||
|
||||
### Providers
|
||||
|
||||
Provider files define LLM providers and their models with pricing, context windows, and capability flags. See [schema.toml](schema.toml) for the full field reference.
|
||||
|
||||
**48 providers** including: Anthropic, OpenAI, Google Gemini, DeepSeek, Groq, Mistral, Cohere, xAI, Together, Fireworks, Ollama (local), LM Studio (local), vLLM (self-hosted), and many more.
|
||||
|
||||
**223 models** with metadata for each: pricing (input/output per token), context window size, capability flags (vision, function calling, streaming), and tier classification.
|
||||
|
||||
### Aliases
|
||||
|
||||
Global model alias mappings in [aliases.toml](aliases.toml) let users reference models by short names:
|
||||
|
||||
```toml
|
||||
"sonnet" = "claude-sonnet-4-6"
|
||||
"gpt4" = "gpt-4o"
|
||||
"flash" = "gemini-2.5-flash"
|
||||
"deepseek" = "deepseek-chat"
|
||||
```
|
||||
|
||||
Models can also define aliases directly in their provider TOML files, which are auto-registered at load time.
|
||||
|
||||
### Plugins
|
||||
|
||||
Plugins extend agent capabilities with memory systems, safety guardrails, and conversation utilities.
|
||||
|
||||
**10 plugins:** auto-summarizer, context-decay, conversation-logger, episodic-memory, guardrails, keyword-memory, sentiment-tracker, todo-tracker, topic-memory, user-profile
|
||||
|
||||
### Skills
|
||||
|
||||
Skills in `skills/<name>/skill.toml` are reusable prompt templates or Python scripts that agents can invoke.
|
||||
Reusable prompt templates or Python scripts that agents can invoke.
|
||||
|
||||
```toml
|
||||
[skill]
|
||||
@@ -112,13 +234,28 @@ type = "promptonly"
|
||||
template = "Create a meeting agenda for: {{topic}}"
|
||||
```
|
||||
|
||||
### Providers
|
||||
### Workflows
|
||||
|
||||
Provider files in `providers/<name>.toml` define LLM providers and their models with pricing, context windows, and capability flags. See [schema.toml](schema.toml) for the full field reference.
|
||||
Pre-built multi-agent workflow definitions in `workflows/<name>.toml` orchestrate multiple agents for complex tasks.
|
||||
|
||||
## How LibreFang Uses This Registry
|
||||
**9 workflows:** brainstorm, code-review, content-pipeline, content-review, customer-support, data-pipeline, research, translate-polish, weekly-report
|
||||
|
||||
LibreFang ships with built-in content compiled into the binary. This repository serves as the upstream source for updates and community contributions.
|
||||
### Templates
|
||||
|
||||
Starter templates in `templates/` for creating new content. Copy a template to get started quickly:
|
||||
|
||||
```bash
|
||||
cp templates/agent.toml agents/my-agent/agent.toml
|
||||
cp templates/HAND.toml hands/my-hand/HAND.toml
|
||||
```
|
||||
|
||||
**6 templates:** agent.toml, HAND.toml, integration.toml, plugin.toml, provider.toml, skill.toml
|
||||
|
||||
See also [docs/content-guide.md](docs/content-guide.md) for naming conventions and contribution guidelines.
|
||||
|
||||
## Usage
|
||||
|
||||
### Install from Registry
|
||||
|
||||
```bash
|
||||
# Update all registry content
|
||||
@@ -133,15 +270,15 @@ librefang integration install github
|
||||
|
||||
### Custom Local Content
|
||||
|
||||
You can also create custom content locally without submitting a PR:
|
||||
Create custom content locally without submitting to this registry:
|
||||
|
||||
```bash
|
||||
# Create a custom agent
|
||||
# Custom agent
|
||||
mkdir -p ~/.librefang/agents/my-agent
|
||||
# Edit ~/.librefang/agents/my-agent/agent.toml
|
||||
|
||||
# Add custom models to your config
|
||||
# ~/.librefang/model_catalog.toml
|
||||
# Custom model aliases
|
||||
# Add to ~/.librefang/model_catalog.toml
|
||||
```
|
||||
|
||||
## Validation
|
||||
@@ -150,9 +287,9 @@ mkdir -p ~/.librefang/agents/my-agent
|
||||
python scripts/validate.py
|
||||
```
|
||||
|
||||
This validates all provider TOML files for correctness: required fields, valid tiers, non-negative costs, no duplicate IDs.
|
||||
Validates all content files for correctness: required fields, valid types, non-negative costs, no duplicate IDs.
|
||||
|
||||
## How to Contribute
|
||||
## Contributing
|
||||
|
||||
1. Fork this repository
|
||||
2. Add or edit content in the appropriate directory
|
||||
@@ -161,19 +298,6 @@ This validates all provider TOML files for correctness: required fields, valid t
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed instructions for each content type.
|
||||
|
||||
## Current Stats
|
||||
|
||||
| Type | Count |
|
||||
|------|-------|
|
||||
| Agents | 33 |
|
||||
| Hands | 14 |
|
||||
| Integrations | 25 |
|
||||
| Skills | 2 |
|
||||
| Plugins | 10 |
|
||||
| Providers | 46 |
|
||||
| Models | 220+ |
|
||||
| Aliases | 80+ |
|
||||
|
||||
## License
|
||||
|
||||
MIT License. See [LICENSE](LICENSE).
|
||||
+27
-7
@@ -10,7 +10,7 @@ Hand definitions for LibreFang. Hands are the user-facing "apps" -- higher-level
|
||||
hands/
|
||||
├── browser/
|
||||
│ ├── HAND.toml # Hand definition
|
||||
│ └── SKILL.md # Documentation
|
||||
│ └── SKILL.md # Expert knowledge for the agent
|
||||
├── trader/
|
||||
│ ├── HAND.toml
|
||||
│ └── SKILL.md
|
||||
@@ -47,6 +47,17 @@ name = "hand-agent"
|
||||
module = "builtin:chat"
|
||||
system_prompt = """..."""
|
||||
|
||||
# Optional: i18n for name, description, category, and settings
|
||||
# Supported languages: zh, ja, ko, es, fr, de
|
||||
[i18n.zh]
|
||||
name = "浏览器 Hand"
|
||||
description = "自主网页浏览器"
|
||||
category = "生产力"
|
||||
|
||||
[i18n.zh.settings.headless] # Per-setting label/description translation
|
||||
label = "无头模式"
|
||||
description = "在后台运行浏览器"
|
||||
|
||||
[dashboard] # Dashboard metrics
|
||||
[[dashboard.metrics]]
|
||||
label = "Tasks Completed"
|
||||
@@ -58,15 +69,24 @@ format = "number"
|
||||
|
||||
| Hand | Category | Description |
|
||||
|------|----------|-------------|
|
||||
| browser | productivity | Autonomous web browser |
|
||||
| trader | data | Crypto/stock trading assistant |
|
||||
| researcher | productivity | Deep research automation |
|
||||
| analytics | data | Data analysis and dashboards |
|
||||
| ... | | See each directory for details |
|
||||
| analytics | data | Data analytics, visualization, dashboards, and automated reporting |
|
||||
| apitester | development | API testing, endpoint discovery, load testing, and regression detection |
|
||||
| browser | productivity | Web navigation, form filling, and multi-step web tasks |
|
||||
| clip | content | Turns long-form video into short clips with captions and thumbnails |
|
||||
| collector | data | Intelligence collection, change detection, and knowledge graphs |
|
||||
| devops | development | CI/CD management, infrastructure monitoring, and incident response |
|
||||
| lead | data | Lead generation, enrichment, scoring, and scheduled delivery |
|
||||
| linkedin | communication | LinkedIn content creation, networking, and engagement |
|
||||
| predictor | data | Signal collection, calibrated predictions, and accuracy tracking |
|
||||
| reddit | communication | Subreddit monitoring, content posting, and engagement tracking |
|
||||
| researcher | productivity | Deep research, cross-referencing, fact-checking, and reports |
|
||||
| strategist | productivity | Market research, competitive analysis, and strategic planning |
|
||||
| trader | data | Market intelligence, multi-signal analysis, and risk management |
|
||||
| twitter | communication | Twitter/X content creation, scheduling, and performance tracking |
|
||||
|
||||
## Adding a New Hand
|
||||
|
||||
1. Create `hands/<name>/HAND.toml` (and optionally `SKILL.md`)
|
||||
1. Create `hands/<name>/HAND.toml` and `SKILL.md` (expert knowledge for the agent)
|
||||
2. Ensure `id` matches the directory name
|
||||
3. Run `python scripts/validate.py`
|
||||
4. Submit a PR
|
||||
|
||||
@@ -484,6 +484,217 @@ token_consumption = "high"
|
||||
default_active = true
|
||||
# Note: High consumption when actively analyzing data, lower when idle
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "数据分析 Hand"
|
||||
description = "自主数据分析智能体——数据采集、分析、可视化、仪表盘和自动化报告"
|
||||
category = "数据"
|
||||
|
||||
[i18n.zh.settings.data_source]
|
||||
label = "数据源"
|
||||
description = "主要数据源类型"
|
||||
|
||||
[i18n.zh.settings.analysis_type]
|
||||
label = "分析类型"
|
||||
description = "默认分析方法"
|
||||
|
||||
[i18n.zh.settings.output_format]
|
||||
label = "输出格式"
|
||||
description = "分析结果的呈现方式"
|
||||
|
||||
[i18n.zh.settings.visualization]
|
||||
label = "可视化"
|
||||
description = "生成图表和可视化内容"
|
||||
|
||||
[i18n.zh.settings.auto_schedule]
|
||||
label = "定时报告"
|
||||
description = "按计划自动生成报告"
|
||||
|
||||
[i18n.zh.settings.report_frequency]
|
||||
label = "报告频率"
|
||||
description = "定时报告的生成频率"
|
||||
|
||||
[i18n.zh.settings.confidence_threshold]
|
||||
label = "置信度阈值"
|
||||
description = "报告中纳入分析结论的最低置信度要求"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "データ分析 Hand"
|
||||
description = "自律型データ分析エージェント——データ収集、分析、可視化、ダッシュボード、自動レポート生成"
|
||||
category = "データ"
|
||||
|
||||
[i18n.ja.settings.data_source]
|
||||
label = "データソース"
|
||||
description = "主要なデータソースの種類"
|
||||
|
||||
[i18n.ja.settings.analysis_type]
|
||||
label = "分析タイプ"
|
||||
description = "デフォルトの分析アプローチ"
|
||||
|
||||
[i18n.ja.settings.output_format]
|
||||
label = "出力形式"
|
||||
description = "分析結果の表示方法"
|
||||
|
||||
[i18n.ja.settings.visualization]
|
||||
label = "可視化"
|
||||
description = "チャートやビジュアライゼーションを生成する"
|
||||
|
||||
[i18n.ja.settings.auto_schedule]
|
||||
label = "定期レポート"
|
||||
description = "スケジュールに基づいてレポートを自動生成する"
|
||||
|
||||
[i18n.ja.settings.report_frequency]
|
||||
label = "レポート頻度"
|
||||
description = "定期レポートの生成頻度"
|
||||
|
||||
[i18n.ja.settings.confidence_threshold]
|
||||
label = "信頼度しきい値"
|
||||
description = "レポートに分析結果を含めるための最低信頼度"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Analítica"
|
||||
description = "Agente autónomo de analítica de datos — recopilación, análisis, visualización, paneles de control e informes automatizados"
|
||||
category = "Datos"
|
||||
|
||||
[i18n.es.settings.data_source]
|
||||
label = "Fuente de datos"
|
||||
description = "Tipo de fuente de datos principal"
|
||||
|
||||
[i18n.es.settings.analysis_type]
|
||||
label = "Tipo de análisis"
|
||||
description = "Enfoque de análisis predeterminado"
|
||||
|
||||
[i18n.es.settings.output_format]
|
||||
label = "Formato de salida"
|
||||
description = "Cómo presentar los resultados del análisis"
|
||||
|
||||
[i18n.es.settings.visualization]
|
||||
label = "Visualización"
|
||||
description = "Generar gráficos y visualizaciones"
|
||||
|
||||
[i18n.es.settings.auto_schedule]
|
||||
label = "Informes programados"
|
||||
description = "Generar informes automáticamente según un calendario"
|
||||
|
||||
[i18n.es.settings.report_frequency]
|
||||
label = "Frecuencia de informes"
|
||||
description = "Con qué frecuencia generar los informes programados"
|
||||
|
||||
[i18n.es.settings.confidence_threshold]
|
||||
label = "Umbral de confianza"
|
||||
description = "Nivel mínimo de confianza para incluir hallazgos en los informes"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand Analytique"
|
||||
description = "Agent autonome d'analyse de données — collecte, analyse, visualisation, tableaux de bord et rapports automatisés"
|
||||
category = "Données"
|
||||
|
||||
[i18n.fr.settings.data_source]
|
||||
label = "Source de données"
|
||||
description = "Type de source de données principal"
|
||||
|
||||
[i18n.fr.settings.analysis_type]
|
||||
label = "Type d'analyse"
|
||||
description = "Approche d'analyse par défaut"
|
||||
|
||||
[i18n.fr.settings.output_format]
|
||||
label = "Format de sortie"
|
||||
description = "Mode de présentation des résultats d'analyse"
|
||||
|
||||
[i18n.fr.settings.visualization]
|
||||
label = "Visualisation"
|
||||
description = "Générer des graphiques et des visualisations"
|
||||
|
||||
[i18n.fr.settings.auto_schedule]
|
||||
label = "Rapports programmés"
|
||||
description = "Générer automatiquement des rapports selon un calendrier"
|
||||
|
||||
[i18n.fr.settings.report_frequency]
|
||||
label = "Fréquence des rapports"
|
||||
description = "Fréquence de génération des rapports programmés"
|
||||
|
||||
[i18n.fr.settings.confidence_threshold]
|
||||
label = "Seuil de confiance"
|
||||
description = "Niveau de confiance minimum pour inclure les résultats dans les rapports"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Analytik-Hand"
|
||||
description = "Autonomer Datenanalyse-Agent — Datenerfassung, Analyse, Visualisierung, Dashboards und automatisierte Berichte"
|
||||
category = "Daten"
|
||||
|
||||
[i18n.de.settings.data_source]
|
||||
label = "Datenquelle"
|
||||
description = "Primärer Datenquellentyp"
|
||||
|
||||
[i18n.de.settings.analysis_type]
|
||||
label = "Analysetyp"
|
||||
description = "Standard-Analyseansatz"
|
||||
|
||||
[i18n.de.settings.output_format]
|
||||
label = "Ausgabeformat"
|
||||
description = "Darstellung der Analyseergebnisse"
|
||||
|
||||
[i18n.de.settings.visualization]
|
||||
label = "Visualisierung"
|
||||
description = "Diagramme und Visualisierungen generieren"
|
||||
|
||||
[i18n.de.settings.auto_schedule]
|
||||
label = "Geplante Berichte"
|
||||
description = "Berichte automatisch nach Zeitplan generieren"
|
||||
|
||||
[i18n.de.settings.report_frequency]
|
||||
label = "Berichtshäufigkeit"
|
||||
description = "Häufigkeit der geplanten Berichtserstellung"
|
||||
|
||||
[i18n.de.settings.confidence_threshold]
|
||||
label = "Konfidenzschwelle"
|
||||
description = "Mindest-Konfidenzniveau für die Aufnahme von Ergebnissen in Berichte"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "데이터 분석 Hand"
|
||||
description = "자율 데이터 분석 에이전트 — 데이터 수집, 분석, 시각화, 대시보드 및 자동화 보고서"
|
||||
category = "데이터"
|
||||
|
||||
[i18n.ko.settings.data_source]
|
||||
label = "데이터 소스"
|
||||
description = "주요 데이터 소스 유형"
|
||||
|
||||
[i18n.ko.settings.analysis_type]
|
||||
label = "분석 유형"
|
||||
description = "기본 분석 방법"
|
||||
|
||||
[i18n.ko.settings.output_format]
|
||||
label = "출력 형식"
|
||||
description = "분석 결과 표시 방식"
|
||||
|
||||
[i18n.ko.settings.visualization]
|
||||
label = "시각화"
|
||||
description = "차트 및 시각화 콘텐츠 생성"
|
||||
|
||||
[i18n.ko.settings.auto_schedule]
|
||||
label = "정기 보고서"
|
||||
description = "일정에 따라 자동으로 보고서 생성"
|
||||
|
||||
[i18n.ko.settings.report_frequency]
|
||||
label = "보고서 빈도"
|
||||
description = "정기 보고서 생성 주기"
|
||||
|
||||
[i18n.ko.settings.confidence_threshold]
|
||||
label = "신뢰도 임계값"
|
||||
description = "보고서에 분석 결과를 포함하기 위한 최소 신뢰도 수준"
|
||||
@@ -337,3 +337,702 @@ Level 4: What to do (prescriptive)
|
||||
| Timeliness | Current | Data refreshed daily |
|
||||
| Uniqueness | 99% | 1% duplicate records found |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: E-commerce Sales Analysis
|
||||
|
||||
**Goal**: Analyze 12 months of order data to identify revenue drivers, customer segments, and growth trends.
|
||||
|
||||
#### Step 1 — Load and clean
|
||||
```python
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
df = pd.read_csv('orders.csv', parse_dates=['order_date'])
|
||||
|
||||
# Quick audit
|
||||
print(f"Rows: {len(df):,} Columns: {df.shape[1]}")
|
||||
print(df.isnull().sum()[df.isnull().sum() > 0])
|
||||
|
||||
# Clean
|
||||
df = df.dropna(subset=['customer_id', 'order_total'])
|
||||
df['order_total'] = df['order_total'].clip(lower=0) # Remove negative values
|
||||
df['order_month'] = df['order_date'].dt.to_period('M')
|
||||
```
|
||||
|
||||
#### Step 2 — Revenue trend analysis
|
||||
```python
|
||||
monthly = (
|
||||
df.groupby('order_month')
|
||||
.agg(revenue=('order_total', 'sum'),
|
||||
orders=('order_id', 'nunique'),
|
||||
customers=('customer_id', 'nunique'))
|
||||
.reset_index()
|
||||
)
|
||||
monthly['aov'] = monthly['revenue'] / monthly['orders'] # Average order value
|
||||
monthly['revenue_mom'] = monthly['revenue'].pct_change() # Month-over-month growth
|
||||
|
||||
fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
|
||||
axes[0].bar(monthly['order_month'].astype(str), monthly['revenue'], color='steelblue')
|
||||
axes[0].set_title('Monthly Revenue', fontsize=14, fontweight='bold')
|
||||
axes[0].set_ylabel('Revenue ($)')
|
||||
|
||||
axes[1].plot(monthly['order_month'].astype(str), monthly['aov'], marker='o', color='coral')
|
||||
axes[1].set_title('Average Order Value', fontsize=14, fontweight='bold')
|
||||
axes[1].set_ylabel('AOV ($)')
|
||||
plt.xticks(rotation=45, ha='right')
|
||||
plt.tight_layout()
|
||||
plt.savefig('revenue_trend.png', dpi=150, bbox_inches='tight')
|
||||
plt.close()
|
||||
```
|
||||
|
||||
#### Step 3 — Customer segmentation (RFM)
|
||||
```python
|
||||
snapshot_date = df['order_date'].max() + pd.Timedelta(days=1)
|
||||
|
||||
rfm = df.groupby('customer_id').agg(
|
||||
recency=('order_date', lambda x: (snapshot_date - x.max()).days),
|
||||
frequency=('order_id', 'nunique'),
|
||||
monetary=('order_total', 'sum')
|
||||
)
|
||||
|
||||
# Score each dimension 1-4 using quartiles
|
||||
for col in ['recency', 'frequency', 'monetary']:
|
||||
labels = [4, 3, 2, 1] if col == 'recency' else [1, 2, 3, 4]
|
||||
rfm[f'{col}_score'] = pd.qcut(rfm[col], q=4, labels=labels, duplicates='drop')
|
||||
|
||||
rfm['rfm_score'] = (rfm['recency_score'].astype(int)
|
||||
+ rfm['frequency_score'].astype(int)
|
||||
+ rfm['monetary_score'].astype(int))
|
||||
|
||||
# Segment mapping
|
||||
def segment(row):
|
||||
r, f, m = int(row['recency_score']), int(row['frequency_score']), int(row['monetary_score'])
|
||||
if r >= 3 and f >= 3:
|
||||
return 'Champions'
|
||||
elif r >= 3 and f < 3:
|
||||
return 'New / Promising'
|
||||
elif r < 3 and f >= 3:
|
||||
return 'At Risk'
|
||||
else:
|
||||
return 'Needs Attention'
|
||||
|
||||
rfm['segment'] = rfm.apply(segment, axis=1)
|
||||
print(rfm.groupby('segment').agg(
|
||||
count=('monetary', 'size'),
|
||||
avg_revenue=('monetary', 'mean'),
|
||||
avg_frequency=('frequency', 'mean')
|
||||
).sort_values('avg_revenue', ascending=False))
|
||||
```
|
||||
|
||||
#### Step 4 — Cohort retention analysis
|
||||
```python
|
||||
df['cohort'] = df.groupby('customer_id')['order_date'].transform('min').dt.to_period('M')
|
||||
df['order_period'] = df['order_date'].dt.to_period('M')
|
||||
df['cohort_index'] = (df['order_period'] - df['cohort']).apply(lambda x: x.n)
|
||||
|
||||
cohort_table = (
|
||||
df.groupby(['cohort', 'cohort_index'])['customer_id']
|
||||
.nunique()
|
||||
.reset_index()
|
||||
.pivot(index='cohort', columns='cohort_index', values='customer_id')
|
||||
)
|
||||
|
||||
# Convert to retention percentages
|
||||
retention = cohort_table.div(cohort_table[0], axis=0) * 100
|
||||
|
||||
fig, ax = plt.subplots(figsize=(14, 8))
|
||||
sns.heatmap(retention, annot=True, fmt='.0f', cmap='YlOrRd_r', ax=ax)
|
||||
ax.set_title('Cohort Retention (% of original customers)', fontsize=14, fontweight='bold')
|
||||
ax.set_xlabel('Months Since First Purchase')
|
||||
ax.set_ylabel('Cohort')
|
||||
plt.tight_layout()
|
||||
plt.savefig('cohort_retention.png', dpi=150, bbox_inches='tight')
|
||||
plt.close()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 2: A/B Test Analysis
|
||||
|
||||
**Goal**: Evaluate whether a new checkout flow (variant B) improves conversion rate over the existing flow (variant A).
|
||||
|
||||
#### Step 1 — Sample size calculation (pre-test)
|
||||
```python
|
||||
from scipy import stats
|
||||
import numpy as np
|
||||
|
||||
baseline_rate = 0.12 # Current conversion rate: 12%
|
||||
mde = 0.02 # Minimum detectable effect: 2 percentage points
|
||||
alpha = 0.05 # Significance level
|
||||
power = 0.80 # Statistical power
|
||||
|
||||
# Using the normal approximation formula
|
||||
p1 = baseline_rate
|
||||
p2 = baseline_rate + mde
|
||||
p_avg = (p1 + p2) / 2
|
||||
|
||||
z_alpha = stats.norm.ppf(1 - alpha / 2) # Two-tailed
|
||||
z_beta = stats.norm.ppf(power)
|
||||
|
||||
n_per_group = ((z_alpha * np.sqrt(2 * p_avg * (1 - p_avg))
|
||||
+ z_beta * np.sqrt(p1 * (1 - p1) + p2 * (1 - p2))) ** 2
|
||||
/ (p2 - p1) ** 2)
|
||||
|
||||
print(f"Required sample size per group: {int(np.ceil(n_per_group)):,}")
|
||||
print(f"Total required: {int(np.ceil(n_per_group)) * 2:,}")
|
||||
```
|
||||
|
||||
#### Step 2 — Run the test and collect results
|
||||
```python
|
||||
ab = pd.read_csv('ab_test_results.csv')
|
||||
|
||||
summary = ab.groupby('variant').agg(
|
||||
visitors=('user_id', 'nunique'),
|
||||
conversions=('converted', 'sum')
|
||||
)
|
||||
summary['conversion_rate'] = summary['conversions'] / summary['visitors']
|
||||
print(summary)
|
||||
```
|
||||
|
||||
#### Step 3 — Statistical significance
|
||||
```python
|
||||
a = ab[ab['variant'] == 'A']
|
||||
b = ab[ab['variant'] == 'B']
|
||||
|
||||
# Chi-squared test for proportions
|
||||
contingency = pd.crosstab(ab['variant'], ab['converted'])
|
||||
chi2, p_value, dof, expected = stats.chi2_contingency(contingency)
|
||||
|
||||
# Proportions z-test (more direct)
|
||||
from statsmodels.stats.proportion import proportions_ztest
|
||||
successes = [summary.loc['B', 'conversions'], summary.loc['A', 'conversions']]
|
||||
trials = [summary.loc['B', 'visitors'], summary.loc['A', 'visitors']]
|
||||
z_stat, p_val = proportions_ztest(successes, trials, alternative='larger')
|
||||
|
||||
print(f"Z-statistic: {z_stat:.4f}")
|
||||
print(f"P-value: {p_val:.4f}")
|
||||
print(f"Significant: {'Yes' if p_val < 0.05 else 'No'} (at alpha=0.05)")
|
||||
```
|
||||
|
||||
#### Step 4 — Effect size and confidence interval
|
||||
```python
|
||||
p_a = summary.loc['A', 'conversion_rate']
|
||||
p_b = summary.loc['B', 'conversion_rate']
|
||||
n_a = summary.loc['A', 'visitors']
|
||||
n_b = summary.loc['B', 'visitors']
|
||||
|
||||
lift = (p_b - p_a) / p_a
|
||||
se_diff = np.sqrt(p_a * (1 - p_a) / n_a + p_b * (1 - p_b) / n_b)
|
||||
ci_lower = (p_b - p_a) - 1.96 * se_diff
|
||||
ci_upper = (p_b - p_a) + 1.96 * se_diff
|
||||
|
||||
print(f"Control rate: {p_a:.4f}")
|
||||
print(f"Variant rate: {p_b:.4f}")
|
||||
print(f"Absolute lift: {p_b - p_a:+.4f}")
|
||||
print(f"Relative lift: {lift:+.2%}")
|
||||
print(f"95% CI for diff: [{ci_lower:+.4f}, {ci_upper:+.4f}]")
|
||||
```
|
||||
|
||||
#### Step 5 — Recommendation template
|
||||
```
|
||||
## A/B Test Report: New Checkout Flow
|
||||
|
||||
| Metric | Control (A) | Variant (B) |
|
||||
|---------------------|-------------|-------------|
|
||||
| Visitors | 15,204 | 15,198 |
|
||||
| Conversions | 1,824 | 2,127 |
|
||||
| Conversion Rate | 12.00% | 13.99% |
|
||||
|
||||
**Result**: Statistically significant (p = 0.0003, alpha = 0.05)
|
||||
**Lift**: +1.99pp absolute / +16.6% relative
|
||||
**95% CI**: [+0.90pp, +3.08pp]
|
||||
**Recommendation**: Deploy variant B. The effect is both statistically
|
||||
and practically significant with a lower bound above the +1pp threshold.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Customer Churn Analysis
|
||||
|
||||
**Goal**: Identify which factors most strongly predict customer churn and quantify their relative importance.
|
||||
|
||||
#### Step 1 — Feature engineering
|
||||
```python
|
||||
df = pd.read_csv('customers.csv')
|
||||
|
||||
# Create behavioral features from raw data
|
||||
features = df.copy()
|
||||
features['tenure_months'] = (pd.Timestamp.now() - pd.to_datetime(df['signup_date'])).dt.days / 30
|
||||
features['support_tickets_per_month'] = df['total_tickets'] / features['tenure_months'].clip(lower=1)
|
||||
features['avg_session_minutes'] = df['total_session_minutes'] / df['total_sessions'].clip(lower=1)
|
||||
features['days_since_last_login'] = (pd.Timestamp.now() - pd.to_datetime(df['last_login'])).dt.days
|
||||
features['has_premium'] = (df['plan'] == 'premium').astype(int)
|
||||
|
||||
# Drop raw columns, keep engineered features
|
||||
feature_cols = [
|
||||
'tenure_months', 'support_tickets_per_month', 'avg_session_minutes',
|
||||
'days_since_last_login', 'has_premium', 'monthly_spend', 'num_features_used'
|
||||
]
|
||||
```
|
||||
|
||||
#### Step 2 — Correlation analysis
|
||||
```python
|
||||
churn_corr = features[feature_cols + ['churned']].corr()['churned'].drop('churned').sort_values()
|
||||
|
||||
fig, ax = plt.subplots(figsize=(8, 5))
|
||||
churn_corr.plot(kind='barh', ax=ax, color=['coral' if x > 0 else 'steelblue' for x in churn_corr])
|
||||
ax.set_title('Feature Correlation with Churn', fontsize=14, fontweight='bold')
|
||||
ax.set_xlabel('Pearson Correlation')
|
||||
ax.axvline(x=0, color='black', linewidth=0.5)
|
||||
plt.tight_layout()
|
||||
plt.savefig('churn_correlations.png', dpi=150, bbox_inches='tight')
|
||||
plt.close()
|
||||
```
|
||||
|
||||
#### Step 3 — Key driver identification via group comparison
|
||||
```python
|
||||
churned = features[features['churned'] == 1]
|
||||
retained = features[features['churned'] == 0]
|
||||
|
||||
comparison = []
|
||||
for col in feature_cols:
|
||||
t_stat, p_val = stats.ttest_ind(churned[col].dropna(), retained[col].dropna())
|
||||
d = cohens_d(churned[col].dropna(), retained[col].dropna()) # From earlier definition
|
||||
comparison.append({
|
||||
'feature': col,
|
||||
'churned_mean': churned[col].mean(),
|
||||
'retained_mean': retained[col].mean(),
|
||||
'diff_pct': (churned[col].mean() - retained[col].mean()) / retained[col].mean() * 100,
|
||||
'cohens_d': abs(d),
|
||||
'p_value': p_val,
|
||||
'significant': p_val < 0.05
|
||||
})
|
||||
|
||||
result = pd.DataFrame(comparison).sort_values('cohens_d', ascending=False)
|
||||
print(result.to_string(index=False))
|
||||
```
|
||||
|
||||
#### Step 4 — Interpret and report
|
||||
```
|
||||
## Churn Driver Analysis
|
||||
|
||||
**Top 3 factors distinguishing churned vs. retained customers:**
|
||||
|
||||
| Factor | Churned (avg) | Retained (avg) | Diff | Effect Size |
|
||||
|----------------------------|---------------|----------------|----------|-------------|
|
||||
| Days since last login | 34.2 | 8.7 | +293% | Large |
|
||||
| Support tickets per month | 2.8 | 0.9 | +211% | Large |
|
||||
| Number of features used | 3.1 | 7.4 | -58% | Medium |
|
||||
|
||||
**Actionable insights:**
|
||||
1. Customers inactive >14 days are 4x more likely to churn -- trigger re-engagement email at day 10
|
||||
2. High support ticket rate signals frustration -- escalate accounts with >2 tickets/month to success team
|
||||
3. Low feature adoption correlates with churn -- implement onboarding flow targeting unused features
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced pandas Patterns
|
||||
|
||||
### Window Functions
|
||||
|
||||
```python
|
||||
# Expanding window (cumulative statistics)
|
||||
df['cumulative_avg'] = df['value'].expanding().mean()
|
||||
df['cumulative_max'] = df['value'].expanding().max()
|
||||
|
||||
# Exponentially weighted moving average (EWMA) -- emphasizes recent values
|
||||
df['ewma_7'] = df['value'].ewm(span=7).mean() # Span-based decay
|
||||
df['ewma_a'] = df['value'].ewm(alpha=0.3).mean() # Explicit decay factor
|
||||
|
||||
# Comparison: rolling vs. EWMA
|
||||
# - rolling(7).mean() weights all 7 values equally
|
||||
# - ewm(span=7).mean() weights recent values exponentially more
|
||||
# Use EWMA when recent data matters more (stock prices, real-time metrics)
|
||||
|
||||
# Rolling with min_periods (handles early rows with insufficient data)
|
||||
df['rolling_avg'] = df['value'].rolling(window=30, min_periods=5).mean()
|
||||
|
||||
# Rolling rank (percentile within window)
|
||||
df['rolling_pctile'] = df['value'].rolling(90).rank(pct=True)
|
||||
```
|
||||
|
||||
### Multi-Index Operations
|
||||
|
||||
```python
|
||||
# Create multi-index from groupby
|
||||
multi = df.groupby(['region', 'product']).agg(
|
||||
revenue=('amount', 'sum'),
|
||||
units=('quantity', 'sum')
|
||||
)
|
||||
|
||||
# Access levels
|
||||
multi.loc['North'] # All products in North region
|
||||
multi.loc[('North', 'Widget')] # Specific region + product
|
||||
multi.xs('Widget', level='product') # All regions for Widget
|
||||
|
||||
# Swap and sort levels
|
||||
multi = multi.swaplevel().sort_index()
|
||||
|
||||
# Reset to flat columns
|
||||
flat = multi.reset_index()
|
||||
|
||||
# Stack / unstack (reshape between long and wide)
|
||||
wide = multi['revenue'].unstack(level='product') # Products become columns
|
||||
long = wide.stack() # Back to multi-index
|
||||
```
|
||||
|
||||
### Merge and Join Patterns
|
||||
|
||||
```python
|
||||
# Inner join (only matching rows)
|
||||
merged = orders.merge(customers, on='customer_id', how='inner')
|
||||
|
||||
# Left join with indicator (see which rows matched)
|
||||
merged = orders.merge(customers, on='customer_id', how='left', indicator=True)
|
||||
unmatched = merged[merged['_merge'] == 'left_only']
|
||||
|
||||
# Join on multiple keys
|
||||
merged = df1.merge(df2, on=['date', 'region'], how='left')
|
||||
|
||||
# Join with different column names
|
||||
merged = orders.merge(products, left_on='prod_id', right_on='product_id')
|
||||
|
||||
# Anti-join (rows in A that have no match in B)
|
||||
anti = df_a.merge(df_b, on='key', how='left', indicator=True)
|
||||
anti = anti[anti['_merge'] == 'left_only'].drop(columns='_merge')
|
||||
|
||||
# Self-join (compare rows within same table)
|
||||
df_prev = df[['customer_id', 'order_date', 'amount']].rename(
|
||||
columns={'order_date': 'prev_date', 'amount': 'prev_amount'}
|
||||
)
|
||||
df_with_prev = df.merge(df_prev, on='customer_id', how='left')
|
||||
df_with_prev = df_with_prev[df_with_prev['prev_date'] < df_with_prev['order_date']]
|
||||
```
|
||||
|
||||
### Apply and Transform
|
||||
|
||||
```python
|
||||
# transform() returns same-shaped output -- useful for group-level stats on each row
|
||||
df['group_mean'] = df.groupby('category')['value'].transform('mean')
|
||||
df['pct_of_group'] = df['value'] / df.groupby('category')['value'].transform('sum')
|
||||
df['z_within_group'] = df.groupby('category')['value'].transform(
|
||||
lambda x: (x - x.mean()) / x.std()
|
||||
)
|
||||
|
||||
# apply() for multi-column group operations
|
||||
def top_n(group, n=3):
|
||||
return group.nlargest(n, 'value')
|
||||
|
||||
top3_per_category = df.groupby('category', group_keys=False).apply(top_n, n=3)
|
||||
|
||||
# Vectorized operations (prefer these over apply when possible)
|
||||
# Slow:
|
||||
df['result'] = df.apply(lambda row: row['a'] * row['b'] + row['c'], axis=1)
|
||||
# Fast:
|
||||
df['result'] = df['a'] * df['b'] + df['c']
|
||||
|
||||
# np.where for conditional columns (vectorized if/else)
|
||||
df['tier'] = np.where(df['revenue'] > 10000, 'high', 'low')
|
||||
|
||||
# np.select for multiple conditions
|
||||
conditions = [
|
||||
df['revenue'] > 10000,
|
||||
df['revenue'] > 5000,
|
||||
df['revenue'] > 0,
|
||||
]
|
||||
choices = ['high', 'medium', 'low']
|
||||
df['tier'] = np.select(conditions, choices, default='none')
|
||||
```
|
||||
|
||||
### Memory Optimization for Large Datasets
|
||||
|
||||
```python
|
||||
# Check current memory usage
|
||||
print(df.memory_usage(deep=True).sum() / 1024**2, "MB")
|
||||
|
||||
# Downcast numeric types
|
||||
df['int_col'] = pd.to_numeric(df['int_col'], downcast='integer') # int64 -> int8/16/32
|
||||
df['float_col'] = pd.to_numeric(df['float_col'], downcast='float') # float64 -> float32
|
||||
|
||||
# Use category type for low-cardinality strings
|
||||
for col in df.select_dtypes(include='object'):
|
||||
if df[col].nunique() / len(df) < 0.5: # Less than 50% unique values
|
||||
df[col] = df[col].astype('category')
|
||||
|
||||
# Read in chunks for files that exceed memory
|
||||
chunks = pd.read_csv('huge_file.csv', chunksize=100_000)
|
||||
results = []
|
||||
for chunk in chunks:
|
||||
processed = chunk.groupby('category')['value'].sum()
|
||||
results.append(processed)
|
||||
final = pd.concat(results).groupby(level=0).sum()
|
||||
|
||||
# Specify dtypes at load time (avoids loading as float64/object first)
|
||||
dtypes = {
|
||||
'id': 'int32',
|
||||
'category': 'category',
|
||||
'value': 'float32',
|
||||
'flag': 'bool'
|
||||
}
|
||||
df = pd.read_csv('data.csv', dtype=dtypes)
|
||||
|
||||
# Use pyarrow backend for better memory efficiency (pandas 2.0+)
|
||||
df = pd.read_csv('data.csv', engine='pyarrow', dtype_backend='pyarrow')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dashboard and Reporting Patterns
|
||||
|
||||
### Executive Dashboard Template
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.gridspec as gridspec
|
||||
from matplotlib.patches import FancyBboxPatch
|
||||
|
||||
def executive_dashboard(kpis, trend_df, comparison_df, output='dashboard.png'):
|
||||
"""
|
||||
kpis: dict with keys like {'Revenue': '$1.2M', 'Growth': '+15%', ...}
|
||||
trend_df: DataFrame with 'date' and 'value' columns
|
||||
comparison_df: DataFrame with 'category' and 'current'/'previous' columns
|
||||
"""
|
||||
fig = plt.figure(figsize=(16, 10))
|
||||
gs = gridspec.GridSpec(3, len(kpis), hspace=0.4, wspace=0.3)
|
||||
|
||||
# Row 1: KPI cards
|
||||
for i, (label, value) in enumerate(kpis.items()):
|
||||
ax = fig.add_subplot(gs[0, i])
|
||||
ax.text(0.5, 0.6, value, ha='center', va='center',
|
||||
fontsize=28, fontweight='bold', color='#2c3e50')
|
||||
ax.text(0.5, 0.2, label, ha='center', va='center',
|
||||
fontsize=12, color='#7f8c8d')
|
||||
ax.set_xlim(0, 1)
|
||||
ax.set_ylim(0, 1)
|
||||
ax.axis('off')
|
||||
# Card background
|
||||
rect = FancyBboxPatch((0.05, 0.05), 0.9, 0.9, boxstyle="round,pad=0.05",
|
||||
facecolor='#f8f9fa', edgecolor='#dee2e6')
|
||||
ax.add_patch(rect)
|
||||
|
||||
# Row 2: Trend line
|
||||
ax_trend = fig.add_subplot(gs[1, :])
|
||||
ax_trend.plot(trend_df['date'], trend_df['value'], linewidth=2, color='steelblue')
|
||||
ax_trend.fill_between(trend_df['date'], trend_df['value'], alpha=0.1, color='steelblue')
|
||||
ax_trend.set_title('Trend Over Time', fontsize=13, fontweight='bold')
|
||||
ax_trend.set_ylabel('Value')
|
||||
|
||||
# Row 3: Period comparison (grouped bar)
|
||||
ax_comp = fig.add_subplot(gs[2, :])
|
||||
x = range(len(comparison_df))
|
||||
width = 0.35
|
||||
ax_comp.bar([i - width/2 for i in x], comparison_df['previous'], width,
|
||||
label='Previous', color='#bdc3c7')
|
||||
ax_comp.bar([i + width/2 for i in x], comparison_df['current'], width,
|
||||
label='Current', color='steelblue')
|
||||
ax_comp.set_xticks(list(x))
|
||||
ax_comp.set_xticklabels(comparison_df['category'], rotation=45, ha='right')
|
||||
ax_comp.set_title('Current vs. Previous Period', fontsize=13, fontweight='bold')
|
||||
ax_comp.legend()
|
||||
|
||||
plt.savefig(output, dpi=150, bbox_inches='tight', facecolor='white')
|
||||
plt.close()
|
||||
```
|
||||
|
||||
### Weekly Metrics Report Template
|
||||
|
||||
```python
|
||||
def weekly_report(df, date_col='date', metric_col='value', group_col=None):
|
||||
"""Generate a standard weekly metrics summary."""
|
||||
df[date_col] = pd.to_datetime(df[date_col])
|
||||
df['week'] = df[date_col].dt.isocalendar().week.astype(int)
|
||||
df['year'] = df[date_col].dt.year
|
||||
|
||||
current_week = df['week'].max()
|
||||
prev_week = current_week - 1
|
||||
|
||||
curr = df[df['week'] == current_week]
|
||||
prev = df[df['week'] == prev_week]
|
||||
|
||||
report = {
|
||||
'period': f"Week {current_week}",
|
||||
'total': curr[metric_col].sum(),
|
||||
'mean': curr[metric_col].mean(),
|
||||
'median': curr[metric_col].median(),
|
||||
'wow_change': (curr[metric_col].sum() - prev[metric_col].sum())
|
||||
/ prev[metric_col].sum() * 100
|
||||
if prev[metric_col].sum() != 0 else None,
|
||||
}
|
||||
|
||||
if group_col:
|
||||
report['by_group'] = curr.groupby(group_col)[metric_col].agg(['sum', 'mean', 'count'])
|
||||
|
||||
# Sparkline trend (last 8 weeks)
|
||||
weekly_totals = (
|
||||
df.groupby('week')[metric_col].sum()
|
||||
.tail(8)
|
||||
.reset_index()
|
||||
)
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6, 2))
|
||||
ax.plot(weekly_totals['week'], weekly_totals[metric_col], marker='o',
|
||||
linewidth=2, color='steelblue', markersize=4)
|
||||
ax.fill_between(weekly_totals['week'], weekly_totals[metric_col],
|
||||
alpha=0.1, color='steelblue')
|
||||
ax.set_title(f'{metric_col.title()} — Last 8 Weeks', fontsize=10)
|
||||
ax.tick_params(labelsize=8)
|
||||
plt.tight_layout()
|
||||
plt.savefig('weekly_sparkline.png', dpi=150, bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
return report
|
||||
```
|
||||
|
||||
### Anomaly Detection Patterns
|
||||
|
||||
```python
|
||||
def detect_anomalies(series, method='zscore', threshold=3.0, window=30):
|
||||
"""
|
||||
Detect anomalies in a numeric series.
|
||||
|
||||
Methods:
|
||||
- 'zscore': Flag values beyond `threshold` standard deviations from mean
|
||||
- 'iqr': Flag values beyond 1.5x IQR from quartiles
|
||||
- 'rolling': Flag values beyond `threshold` std devs from rolling mean
|
||||
"""
|
||||
anomalies = pd.Series(False, index=series.index)
|
||||
|
||||
if method == 'zscore':
|
||||
z = (series - series.mean()) / series.std()
|
||||
anomalies = z.abs() > threshold
|
||||
|
||||
elif method == 'iqr':
|
||||
q1 = series.quantile(0.25)
|
||||
q3 = series.quantile(0.75)
|
||||
iqr = q3 - q1
|
||||
anomalies = (series < q1 - 1.5 * iqr) | (series > q3 + 1.5 * iqr)
|
||||
|
||||
elif method == 'rolling':
|
||||
rolling_mean = series.rolling(window, min_periods=5).mean()
|
||||
rolling_std = series.rolling(window, min_periods=5).std()
|
||||
anomalies = (series - rolling_mean).abs() > threshold * rolling_std
|
||||
|
||||
return anomalies
|
||||
|
||||
|
||||
# Usage: detect and visualize
|
||||
anomalies = detect_anomalies(df['metric'], method='rolling', threshold=2.5, window=30)
|
||||
|
||||
fig, ax = plt.subplots(figsize=(14, 5))
|
||||
ax.plot(df.index, df['metric'], linewidth=1, color='steelblue', label='Metric')
|
||||
ax.scatter(df.index[anomalies], df['metric'][anomalies],
|
||||
color='red', s=40, zorder=5, label='Anomaly')
|
||||
ax.legend()
|
||||
ax.set_title('Anomaly Detection (Rolling Z-Score)', fontsize=14, fontweight='bold')
|
||||
plt.tight_layout()
|
||||
plt.savefig('anomalies.png', dpi=150, bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
print(f"Detected {anomalies.sum()} anomalies out of {len(series):,} data points")
|
||||
```
|
||||
|
||||
**Method selection guide:**
|
||||
|
||||
| Method | Best For | Assumptions | Sensitivity |
|
||||
|--------|----------|-------------|-------------|
|
||||
| Z-score | Stationary data with normal distribution | Constant mean and variance | Low (misses local anomalies) |
|
||||
| IQR | Skewed distributions, outlier screening | None (non-parametric) | Medium |
|
||||
| Rolling z-score | Time series with trends or seasonality | Local stationarity within window | High (adapts to drift) |
|
||||
|
||||
---
|
||||
|
||||
## Common Analytics Pitfalls
|
||||
|
||||
### Simpson's Paradox
|
||||
|
||||
A trend that appears in grouped data reverses when the groups are combined.
|
||||
|
||||
```
|
||||
Department A: Drug works better (80% vs 70%)
|
||||
Department B: Drug works better (50% vs 40%)
|
||||
Combined: Drug appears WORSE (55% vs 60%) <-- paradox
|
||||
```
|
||||
|
||||
**Why it happens**: Unequal group sizes create a confounding effect. Department B (with lower overall rates) sent most patients to the drug group.
|
||||
|
||||
**Prevention**: Always segment data by relevant confounders before drawing conclusions. If aggregate and segmented results disagree, trust the segmented analysis and report the confounding variable.
|
||||
|
||||
### Survivorship Bias
|
||||
|
||||
Analyzing only entities that "survived" a selection process, ignoring those that dropped out.
|
||||
|
||||
**Classic examples:**
|
||||
- Studying only successful companies to find success patterns (ignoring failed companies with the same patterns)
|
||||
- Analyzing only current customers to understand satisfaction (ignoring those who already left)
|
||||
- Looking at fund performance by examining only funds that still exist (dead funds were closed)
|
||||
|
||||
**Prevention**: Always ask "what is missing from this dataset?" before drawing conclusions. If possible, include data from non-survivors. Explicitly note the selection criteria and what it excludes.
|
||||
|
||||
### Correlation vs. Causation
|
||||
|
||||
A statistically significant correlation between X and Y does not mean X causes Y. Possible explanations:
|
||||
|
||||
| Explanation | Example |
|
||||
|-------------|---------|
|
||||
| X causes Y | Exercise reduces blood pressure |
|
||||
| Y causes X | Depression reduces exercise (not exercise causes depression) |
|
||||
| Z causes both | Income drives both education spending AND health outcomes |
|
||||
| Coincidence | Ice cream sales correlate with drowning deaths (both driven by summer) |
|
||||
|
||||
**Prevention**: Establish causation only with randomized controlled experiments (A/B tests). For observational data, state findings as "associated with" not "causes." Look for confounders and test whether the relationship holds when controlling for them.
|
||||
|
||||
### Cherry-Picking Time Windows
|
||||
|
||||
Selecting a start/end date that makes a metric look better or worse than the true trend.
|
||||
|
||||
```python
|
||||
# Example: same data, different conclusions
|
||||
# "Revenue up 40%!" -- comparing Jan (seasonal low) to Dec (seasonal high)
|
||||
# "Revenue flat." -- comparing Dec 2024 to Dec 2025 (year-over-year)
|
||||
|
||||
# Prevention: always use year-over-year comparison for seasonal data
|
||||
df['yoy_change'] = df.groupby(df['date'].dt.month)['revenue'].pct_change(periods=12)
|
||||
```
|
||||
|
||||
**Prevention checklist:**
|
||||
- Compare like-for-like periods (YoY for seasonal businesses)
|
||||
- Show the full time range, not a selected subset
|
||||
- Use multiple time windows (WoW, MoM, QoQ, YoY) and note if they disagree
|
||||
- Include a moving average to show the underlying trend separate from noise
|
||||
|
||||
### Small Sample Size Issues
|
||||
|
||||
Small samples produce unstable statistics that can flip with just a few more observations.
|
||||
|
||||
```python
|
||||
# Illustrate instability: conversion rates with small vs. large samples
|
||||
from scipy.stats import beta
|
||||
|
||||
# Scenario: 3 conversions out of 10 visitors (30%)
|
||||
a_small, b_small = 3 + 1, 10 - 3 + 1 # Beta posterior
|
||||
ci_small = beta.interval(0.95, a_small, b_small)
|
||||
print(f"n=10: 30% conversion, 95% CI: [{ci_small[0]:.1%}, {ci_small[1]:.1%}]")
|
||||
# Output: 95% CI: [9.9%, 56.8%] -- extremely wide, almost useless
|
||||
|
||||
# Scenario: 300 conversions out of 1000 visitors (30%)
|
||||
a_large, b_large = 300 + 1, 1000 - 300 + 1
|
||||
ci_large = beta.interval(0.95, a_large, b_large)
|
||||
print(f"n=1000: 30% conversion, 95% CI: [{ci_large[0]:.1%}, {ci_large[1]:.1%}]")
|
||||
# Output: 95% CI: [27.2%, 32.9%] -- narrow and actionable
|
||||
```
|
||||
|
||||
**Rules of thumb:**
|
||||
- n < 30: Do not draw firm conclusions. Report as directional only.
|
||||
- Conversion rates need hundreds (not dozens) of conversions to stabilize.
|
||||
- Always report confidence intervals alongside point estimates.
|
||||
- If sample size is fixed and small, use exact tests (Fisher's exact) rather than approximations (chi-squared).
|
||||
+358
-14
@@ -302,9 +302,26 @@ If `approval_mode` is ENABLED:
|
||||
If `approval_mode` is DISABLED:
|
||||
Execute load tests directly.
|
||||
|
||||
### Structured Load Test Profiles
|
||||
|
||||
Run profiles in order. Each answers a different question. Stop a profile early if exit criteria are met.
|
||||
|
||||
**Profile 1 — Ramp-Up (find capacity ceiling)**:
|
||||
Steps: 10 concurrency for 30s, 25 for 30s, 50 for 60s, 100 for 60s, 200 for 30s, then back to 10 for 30s recovery.
|
||||
Exit: stop stepping up when error rate >10% or p95 >2s. Record last healthy step as "max safe concurrency."
|
||||
|
||||
**Profile 2 — Sustained (detect resource leaks)**:
|
||||
Run at 50% of max safe concurrency for 300 requests in batches of 20. Compare average response time of first quarter vs last quarter. A >25% increase signals connection pool exhaustion or memory growth.
|
||||
|
||||
**Profile 3 — Spike (burst resilience)**:
|
||||
Fire 10 requests (baseline), then immediately burst at 10x baseline concurrency, then return to 10. Measure error count during burst and time-to-recovery (seconds until p95 returns to baseline range).
|
||||
|
||||
**Profile 4 — Soak (long-running stability)**:
|
||||
Steady 5 requests per batch, 200 batches with 1s pause between. Track response time trend. Flag if final-quarter average exceeds first-quarter average by >30%.
|
||||
|
||||
Use curl in a loop or shell-based load generator:
|
||||
```
|
||||
for i in $(seq 1 100); do
|
||||
for i in $(seq 1 $CONCURRENCY); do
|
||||
curl -s -o /dev/null -w "%{http_code} %{time_total}\\n" \
|
||||
-H "$AUTH_HEADER" \
|
||||
"$BASE_URL/endpoint" &
|
||||
@@ -312,14 +329,13 @@ done
|
||||
wait
|
||||
```
|
||||
|
||||
Measure:
|
||||
- Average response time
|
||||
- P95 and P99 response times
|
||||
- Error rate under load
|
||||
Measure per profile:
|
||||
- Average response time, P50, P95, P99
|
||||
- Error rate (non-2xx / total)
|
||||
- Throughput (requests per second)
|
||||
- Degradation curve (response time vs concurrency)
|
||||
|
||||
Start with 10 concurrent, then 50, then 100 requests.
|
||||
- Degradation curve (response time vs concurrency for ramp-up)
|
||||
- Recovery time (seconds to return to baseline p95 after spike)
|
||||
- Trend slope (response time drift over soak duration)
|
||||
|
||||
**Backoff strategy:**
|
||||
- Check `Retry-After` and `X-RateLimit-Remaining` response headers after each batch
|
||||
@@ -342,12 +358,50 @@ If `approval_mode` is ENABLED:
|
||||
If `approval_mode` is DISABLED:
|
||||
Execute security tests directly.
|
||||
|
||||
1. **Authentication tests**: Missing auth, invalid auth, expired tokens
|
||||
2. **Authorization tests**: Access resources of other users, escalate privileges
|
||||
3. **Input injection**: SQL injection, XSS, command injection in parameters
|
||||
4. **Headers**: Missing security headers (CORS, HSTS, X-Frame-Options)
|
||||
5. **Rate limiting**: Verify rate limits are enforced
|
||||
6. **Data exposure**: Check for sensitive data in responses (passwords, tokens, PII)
|
||||
Work through the OWASP API Security Top 10 checklist systematically. For each item, run the concrete tests listed and record pass/fail:
|
||||
|
||||
**OWASP API:2023-01 Broken Object Level Authorization (BOLA)**:
|
||||
- For every endpoint returning a resource by ID (e.g. `/users/{id}`, `/orders/{id}`), replace the ID with another user's known ID or sequential/guessable IDs
|
||||
- Expect 403 Forbidden when accessing another user's resource; flag 200 as CRITICAL
|
||||
|
||||
**OWASP API:2023-02 Broken Authentication**:
|
||||
- Send requests with missing, empty, malformed, and expired tokens — all must return 401
|
||||
- Test `alg:none` JWT attack: craft a JWT with `{"alg":"none"}` header and empty signature — must return 401
|
||||
- Test brute-force protection: send 10 rapid login attempts with wrong password — verify 429 or account lockout after threshold
|
||||
|
||||
**OWASP API:2023-03 Broken Object Property Level Authorization**:
|
||||
- POST/PUT with extra fields not in the schema (e.g. `"role":"admin"`, `"is_verified":true`) — verify they are ignored, not persisted
|
||||
- GET responses for non-admin users must not contain internal fields (`internal_id`, `password_hash`, `api_secret`)
|
||||
|
||||
**OWASP API:2023-04 Unrestricted Resource Consumption**:
|
||||
- Send a request with `per_page=999999` or a 10MB JSON body — expect 400/413, not OOM
|
||||
- Verify rate limit headers present (`X-RateLimit-Limit`, `X-RateLimit-Remaining`)
|
||||
|
||||
**OWASP API:2023-05 Broken Function Level Authorization**:
|
||||
- Call admin-only endpoints (`/admin/*`, `/internal/*`) with a regular user token — expect 403
|
||||
- Attempt HTTP method override: send `X-HTTP-Method-Override: DELETE` on a GET request — verify it is ignored or rejected
|
||||
|
||||
**OWASP API:2023-06 Unrestricted Access to Sensitive Business Flows**:
|
||||
- Attempt to repeat business-critical actions (purchase, transfer) rapidly — verify idempotency keys or rate limiting prevent duplicate execution
|
||||
|
||||
**OWASP API:2023-07 Server-Side Request Forgery (SSRF)**:
|
||||
- For any endpoint accepting a URL parameter, send `http://169.254.169.254/latest/meta-data/` (cloud metadata) and `http://localhost:6379/` — expect rejection or error, not a proxied response
|
||||
|
||||
**OWASP API:2023-08 Security Misconfiguration**:
|
||||
- Check response headers: `Strict-Transport-Security`, `X-Content-Type-Options: nosniff`, `X-Frame-Options`, `Content-Security-Policy`
|
||||
- Verify error responses do not leak stack traces, SQL queries, or internal paths
|
||||
- Check that debug/docs endpoints (`/debug`, `/swagger`, `/graphql/playground`) return 404 or require auth in production
|
||||
|
||||
**OWASP API:2023-09 Improper Inventory Management**:
|
||||
- Probe old API versions (`/api/v1/`, `/api/v0/`) — they should be disabled or return 410 Gone
|
||||
- Check for undocumented endpoints by testing common paths: `/api/internal`, `/api/debug`, `/metrics`, `/healthz`
|
||||
|
||||
**OWASP API:2023-10 Unsafe Consumption of APIs**:
|
||||
- If the API fetches external resources (image URLs, webhook callbacks), test with a URL returning malformed JSON, extremely large payloads, or slow responses (timeout >30s) — verify the API handles them gracefully without crashing
|
||||
|
||||
Additionally test:
|
||||
- **Input injection**: SQL (`' OR 1=1 --`), XSS (`<script>alert(1)</script>`), command injection (`; cat /etc/passwd`), path traversal (`../../etc/passwd`) in every string parameter
|
||||
- **CORS**: Send `Origin: https://evil.example.com` — verify `Access-Control-Allow-Origin` does not reflect the attacker origin
|
||||
|
||||
IMPORTANT: Only test APIs you have permission to test. Never perform destructive tests without explicit confirmation.
|
||||
|
||||
@@ -361,6 +415,37 @@ Stop testing when ANY of these conditions is met:
|
||||
|
||||
---
|
||||
|
||||
## Phase 5.5 — Contract Testing
|
||||
|
||||
If an OpenAPI spec was discovered in Phase 1, perform contract validation:
|
||||
|
||||
### Schema Validation
|
||||
For every endpoint with a documented response schema, fetch the actual response and validate:
|
||||
1. All `required` fields are present
|
||||
2. Every field matches its declared `type` and `format` (e.g. `string`/`date-time`, `integer`/`int64`)
|
||||
3. `enum` fields contain only allowed values
|
||||
4. `additionalProperties: false` schemas reject extra fields
|
||||
5. Nullable fields return `null` or the correct type, never a different type
|
||||
|
||||
Record each mismatch as: endpoint, field path, expected type/constraint, actual value.
|
||||
|
||||
### Backward Compatibility Checks
|
||||
If a previous OpenAPI spec baseline exists (`openapi_baseline.json`):
|
||||
1. **Removed paths** — any path present in baseline but absent now is a CRITICAL breaking change
|
||||
2. **Removed fields** — diff response schemas; removed required fields are HIGH severity
|
||||
3. **Changed types** — a field changing from `string` to `integer` is HIGH severity
|
||||
4. **New required request fields** — breaks existing callers, HIGH severity
|
||||
5. **Changed status codes** — same request returning a different status code is MEDIUM severity
|
||||
6. **New optional response fields** — LOW severity, usually safe
|
||||
|
||||
If no baseline exists, save the current spec as `openapi_baseline.json` for future comparisons.
|
||||
|
||||
### Content-Type Negotiation
|
||||
- Send `Accept: application/xml` to a JSON-only endpoint — expect 406 Not Acceptable or graceful JSON fallback, not a 500
|
||||
- Send `Content-Type: text/plain` with a JSON body — expect 415 Unsupported Media Type
|
||||
|
||||
---
|
||||
|
||||
## Phase 6 — Report Generation
|
||||
|
||||
Generate a comprehensive test report:
|
||||
@@ -460,6 +545,265 @@ token_consumption = "medium"
|
||||
default_active = false
|
||||
activation_warning = "API Tester hand runs continuously, consuming tokens. Use on-demand for specific tests."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "API 测试 Hand"
|
||||
description = "自主 API 测试智能体——端点发现、请求验证、负载测试和回归检测"
|
||||
category = "开发"
|
||||
|
||||
[i18n.zh.settings.base_url]
|
||||
label = "基础 URL"
|
||||
description = "待测试 API 的基础 URL(例如 https://api.example.com/v1)"
|
||||
|
||||
[i18n.zh.settings.auth_type]
|
||||
label = "认证方式"
|
||||
description = "API 请求的认证方式"
|
||||
|
||||
[i18n.zh.settings.auth_token]
|
||||
label = "认证令牌 / API 密钥"
|
||||
description = "Bearer 令牌、API 密钥或 Base64 编码的凭据,取决于认证方式"
|
||||
|
||||
[i18n.zh.settings.test_mode]
|
||||
label = "测试模式"
|
||||
description = "执行的 API 测试类型"
|
||||
|
||||
[i18n.zh.settings.openapi_spec_url]
|
||||
label = "OpenAPI 规范 URL"
|
||||
description = "OpenAPI/Swagger 规范的 URL(例如 /openapi.json)。留空则自动发现。"
|
||||
|
||||
[i18n.zh.settings.auto_schedule]
|
||||
label = "自动定时"
|
||||
description = "按计划自动运行测试"
|
||||
|
||||
[i18n.zh.settings.test_frequency]
|
||||
label = "测试频率"
|
||||
description = "定时测试的执行频率"
|
||||
|
||||
[i18n.zh.settings.fail_on_error]
|
||||
label = "严格模式"
|
||||
description = "将任何非 2xx 响应视为失败(而非允许预期的错误码)"
|
||||
|
||||
[i18n.zh.settings.approval_mode]
|
||||
label = "审批模式"
|
||||
description = "将测试计划和破坏性请求写入队列文件供审核,而非直接执行"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "APIテスト Hand"
|
||||
description = "自律型APIテストエージェント——エンドポイント検出、リクエスト検証、負荷テスト、リグレッション検出"
|
||||
category = "開発"
|
||||
|
||||
[i18n.ja.settings.base_url]
|
||||
label = "ベースURL"
|
||||
description = "テスト対象APIのベースURL(例: https://api.example.com/v1)"
|
||||
|
||||
[i18n.ja.settings.auth_type]
|
||||
label = "認証方式"
|
||||
description = "APIリクエストの認証方法"
|
||||
|
||||
[i18n.ja.settings.auth_token]
|
||||
label = "認証トークン / APIキー"
|
||||
description = "認証方式に応じたBearerトークン、APIキー、またはBase64エンコードされた資格情報"
|
||||
|
||||
[i18n.ja.settings.test_mode]
|
||||
label = "テストモード"
|
||||
description = "実行するAPIテストの種類"
|
||||
|
||||
[i18n.ja.settings.openapi_spec_url]
|
||||
label = "OpenAPI仕様URL"
|
||||
description = "OpenAPI/Swagger仕様のURL(例: /openapi.json)。空欄にすると自動検出します。"
|
||||
|
||||
[i18n.ja.settings.auto_schedule]
|
||||
label = "自動スケジュール"
|
||||
description = "スケジュールに基づいてテストを自動実行する"
|
||||
|
||||
[i18n.ja.settings.test_frequency]
|
||||
label = "テスト頻度"
|
||||
description = "定期テストの実行頻度"
|
||||
|
||||
[i18n.ja.settings.fail_on_error]
|
||||
label = "厳格モード"
|
||||
description = "2xx以外のレスポンスをすべて失敗として扱う(期待されるエラーコードを許容しない)"
|
||||
|
||||
[i18n.ja.settings.approval_mode]
|
||||
label = "承認モード"
|
||||
description = "テスト計画や破壊的リクエストを直接実行せず、レビュー用のキューファイルに書き出す"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Pruebas API"
|
||||
description = "Agente autónomo de pruebas de API — descubrimiento de endpoints, validación de peticiones, pruebas de carga y detección de regresiones"
|
||||
category = "Desarrollo"
|
||||
|
||||
[i18n.es.settings.base_url]
|
||||
label = "URL base"
|
||||
description = "URL base de la API a probar (ej. https://api.example.com/v1)"
|
||||
|
||||
[i18n.es.settings.auth_type]
|
||||
label = "Tipo de autenticación"
|
||||
description = "Cómo autenticar las peticiones a la API"
|
||||
|
||||
[i18n.es.settings.auth_token]
|
||||
label = "Token de autenticación / Clave API"
|
||||
description = "Token Bearer, clave API o credenciales codificadas en Base64 según el tipo de autenticación"
|
||||
|
||||
[i18n.es.settings.test_mode]
|
||||
label = "Modo de prueba"
|
||||
description = "Qué tipo de pruebas de API realizar"
|
||||
|
||||
[i18n.es.settings.openapi_spec_url]
|
||||
label = "URL de especificación OpenAPI"
|
||||
description = "URL de la especificación OpenAPI/Swagger (ej. /openapi.json). Dejar vacío para descubrimiento automático."
|
||||
|
||||
[i18n.es.settings.auto_schedule]
|
||||
label = "Programación automática"
|
||||
description = "Ejecutar pruebas automáticamente según un calendario"
|
||||
|
||||
[i18n.es.settings.test_frequency]
|
||||
label = "Frecuencia de pruebas"
|
||||
description = "Con qué frecuencia ejecutar las pruebas programadas"
|
||||
|
||||
[i18n.es.settings.fail_on_error]
|
||||
label = "Modo estricto"
|
||||
description = "Tratar cualquier respuesta no 2xx como un fallo (en lugar de permitir códigos de error esperados)"
|
||||
|
||||
[i18n.es.settings.approval_mode]
|
||||
label = "Modo de aprobación"
|
||||
description = "Escribir planes de prueba y peticiones destructivas en un archivo de cola para revisión en lugar de ejecutarlos directamente"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand de Test API"
|
||||
description = "Agent autonome de test d'API — découverte de points de terminaison, validation de requêtes, tests de charge et détection de régression"
|
||||
category = "Développement"
|
||||
|
||||
[i18n.fr.settings.base_url]
|
||||
label = "URL de base"
|
||||
description = "URL de base de l'API à tester (ex. https://api.example.com/v1)"
|
||||
|
||||
[i18n.fr.settings.auth_type]
|
||||
label = "Type d'authentification"
|
||||
description = "Méthode d'authentification des requêtes API"
|
||||
|
||||
[i18n.fr.settings.auth_token]
|
||||
label = "Jeton d'authentification / Clé API"
|
||||
description = "Jeton Bearer, clé API ou identifiants encodés en Base64 selon le type d'authentification"
|
||||
|
||||
[i18n.fr.settings.test_mode]
|
||||
label = "Mode de test"
|
||||
description = "Type de tests API à exécuter"
|
||||
|
||||
[i18n.fr.settings.openapi_spec_url]
|
||||
label = "URL de spécification OpenAPI"
|
||||
description = "URL de la spécification OpenAPI/Swagger (ex. /openapi.json). Laisser vide pour la découverte automatique."
|
||||
|
||||
[i18n.fr.settings.auto_schedule]
|
||||
label = "Planification automatique"
|
||||
description = "Exécuter automatiquement les tests selon un calendrier"
|
||||
|
||||
[i18n.fr.settings.test_frequency]
|
||||
label = "Fréquence des tests"
|
||||
description = "Fréquence d'exécution des tests planifiés"
|
||||
|
||||
[i18n.fr.settings.fail_on_error]
|
||||
label = "Mode strict"
|
||||
description = "Traiter toute réponse non 2xx comme un échec (au lieu d'autoriser les codes d'erreur attendus)"
|
||||
|
||||
[i18n.fr.settings.approval_mode]
|
||||
label = "Mode d'approbation"
|
||||
description = "Écrire les plans de test et requêtes destructives dans un fichier d'attente pour révision au lieu de les exécuter directement"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "API-Test-Hand"
|
||||
description = "Autonomer API-Test-Agent — Endpunkt-Erkennung, Anfrage-Validierung, Lasttests und Regressionserkennung"
|
||||
category = "Entwicklung"
|
||||
|
||||
[i18n.de.settings.base_url]
|
||||
label = "Basis-URL"
|
||||
description = "Basis-URL der zu testenden API (z.B. https://api.example.com/v1)"
|
||||
|
||||
[i18n.de.settings.auth_type]
|
||||
label = "Authentifizierungstyp"
|
||||
description = "Authentifizierungsmethode für API-Anfragen"
|
||||
|
||||
[i18n.de.settings.auth_token]
|
||||
label = "Authentifizierungstoken / API-Schlüssel"
|
||||
description = "Bearer-Token, API-Schlüssel oder Base64-kodierte Anmeldedaten je nach Authentifizierungstyp"
|
||||
|
||||
[i18n.de.settings.test_mode]
|
||||
label = "Testmodus"
|
||||
description = "Art der durchzuführenden API-Tests"
|
||||
|
||||
[i18n.de.settings.openapi_spec_url]
|
||||
label = "OpenAPI-Spezifikations-URL"
|
||||
description = "URL der OpenAPI/Swagger-Spezifikation (z.B. /openapi.json). Leer lassen für automatische Erkennung."
|
||||
|
||||
[i18n.de.settings.auto_schedule]
|
||||
label = "Automatische Planung"
|
||||
description = "Tests automatisch nach Zeitplan ausführen"
|
||||
|
||||
[i18n.de.settings.test_frequency]
|
||||
label = "Testhäufigkeit"
|
||||
description = "Ausführungshäufigkeit der geplanten Tests"
|
||||
|
||||
[i18n.de.settings.fail_on_error]
|
||||
label = "Strikter Modus"
|
||||
description = "Jede Nicht-2xx-Antwort als Fehler behandeln (anstatt erwartete Fehlercodes zuzulassen)"
|
||||
|
||||
[i18n.de.settings.approval_mode]
|
||||
label = "Genehmigungsmodus"
|
||||
description = "Testpläne und destruktive Anfragen in eine Warteschlange zur Überprüfung schreiben, anstatt sie direkt auszuführen"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "API 테스트 Hand"
|
||||
description = "자율 API 테스트 에이전트 — 엔드포인트 탐색, 요청 검증, 부하 테스트 및 회귀 감지"
|
||||
category = "개발"
|
||||
|
||||
[i18n.ko.settings.base_url]
|
||||
label = "기본 URL"
|
||||
description = "테스트할 API의 기본 URL (예: https://api.example.com/v1)"
|
||||
|
||||
[i18n.ko.settings.auth_type]
|
||||
label = "인증 방식"
|
||||
description = "API 요청의 인증 방식"
|
||||
|
||||
[i18n.ko.settings.auth_token]
|
||||
label = "인증 토큰 / API 키"
|
||||
description = "인증 방식에 따른 Bearer 토큰, API 키 또는 Base64 인코딩 자격 증명"
|
||||
|
||||
[i18n.ko.settings.test_mode]
|
||||
label = "테스트 모드"
|
||||
description = "수행할 API 테스트 유형"
|
||||
|
||||
[i18n.ko.settings.openapi_spec_url]
|
||||
label = "OpenAPI 스펙 URL"
|
||||
description = "OpenAPI/Swagger 스펙의 URL (예: /openapi.json). 비워두면 자동 탐색합니다."
|
||||
|
||||
[i18n.ko.settings.auto_schedule]
|
||||
label = "자동 일정"
|
||||
description = "일정에 따라 자동으로 테스트 실행"
|
||||
|
||||
[i18n.ko.settings.test_frequency]
|
||||
label = "테스트 빈도"
|
||||
description = "정기 테스트 실행 주기"
|
||||
|
||||
[i18n.ko.settings.fail_on_error]
|
||||
label = "엄격 모드"
|
||||
description = "모든 비-2xx 응답을 실패로 처리 (예상된 오류 코드 허용 안 함)"
|
||||
|
||||
[i18n.ko.settings.approval_mode]
|
||||
label = "승인 모드"
|
||||
description = "테스트 계획 및 파괴적 요청을 직접 실행하지 않고 큐 파일에 기록하여 검토"
|
||||
@@ -237,3 +237,713 @@ First Seen: 2025-01-15 run
|
||||
Previous Value: string (email format)
|
||||
Current Value: field absent
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Testing a REST API CRUD Endpoint
|
||||
|
||||
Full test suite for a `/api/users` resource covering create, read, update, delete, and edge cases.
|
||||
|
||||
**Setup — Create a test user**:
|
||||
```bash
|
||||
# POST /api/users — create
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"name": "Ada Lovelace", "email": "ada@example.com", "role": "engineer"}' \
|
||||
"https://api.example.com/api/users")
|
||||
|
||||
BODY=$(echo "$RESPONSE" | sed '$d')
|
||||
STATUS=$(echo "$RESPONSE" | tail -1)
|
||||
|
||||
# Expect 201 Created
|
||||
[ "$STATUS" = "201" ] && echo "PASS: Create user" || echo "FAIL: Expected 201, got $STATUS"
|
||||
|
||||
# Extract ID for subsequent tests
|
||||
USER_ID=$(echo "$BODY" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
||||
```
|
||||
|
||||
**Read operations**:
|
||||
```bash
|
||||
# GET /api/users — list all
|
||||
curl -s -H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/users" | python3 -m json.tool
|
||||
|
||||
# GET /api/users/:id — single user
|
||||
curl -s -H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/users/$USER_ID" | python3 -m json.tool
|
||||
|
||||
# GET /api/users/nonexistent-id — expect 404
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/users/00000000-0000-0000-0000-000000000000")
|
||||
[ "$STATUS" = "404" ] && echo "PASS: 404 for missing user" || echo "FAIL: Expected 404, got $STATUS"
|
||||
```
|
||||
|
||||
**Update operations**:
|
||||
```bash
|
||||
# PUT /api/users/:id — full update
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X PUT \
|
||||
-H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"name": "Ada Lovelace", "email": "ada.updated@example.com", "role": "lead"}' \
|
||||
"https://api.example.com/api/users/$USER_ID")
|
||||
[ "$STATUS" = "200" ] && echo "PASS: Full update" || echo "FAIL: Expected 200, got $STATUS"
|
||||
|
||||
# PATCH — partial update (expect 200); also test invalid data (expect 400/422)
|
||||
```
|
||||
|
||||
**Delete and verify**:
|
||||
```bash
|
||||
# DELETE /api/users/:id
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/users/$USER_ID")
|
||||
[ "$STATUS" = "204" ] || [ "$STATUS" = "200" ] && echo "PASS: Delete user" || echo "FAIL: Expected 2xx, got $STATUS"
|
||||
|
||||
# GET deleted user — expect 404 or 410
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/users/$USER_ID")
|
||||
[ "$STATUS" = "404" ] || [ "$STATUS" = "410" ] && echo "PASS: Deleted user gone" || echo "FAIL: Expected 404/410, got $STATUS"
|
||||
|
||||
# DELETE again — idempotency check
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/users/$USER_ID")
|
||||
[ "$STATUS" = "404" ] || [ "$STATUS" = "204" ] && echo "PASS: Idempotent delete" || echo "FAIL: Got $STATUS"
|
||||
```
|
||||
|
||||
**Edge cases to test**: duplicate create (expect 409), empty body (expect 400/422), extra unknown fields (verify ignored or rejected, not persisted).
|
||||
|
||||
### Example 2: Testing an Authenticated API with Rate Limiting
|
||||
|
||||
Scenario: API uses Bearer tokens, tokens expire after 1 hour, rate limit is 100 requests/minute.
|
||||
|
||||
**Token lifecycle testing**:
|
||||
```bash
|
||||
# Step 1: Obtain token
|
||||
AUTH_RESPONSE=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"client_id": "myapp", "client_secret": "secret", "grant_type": "client_credentials"}' \
|
||||
"https://api.example.com/oauth/token")
|
||||
|
||||
ACCESS_TOKEN=$(echo "$AUTH_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
|
||||
EXPIRES_IN=$(echo "$AUTH_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['expires_in'])")
|
||||
echo "Token obtained, expires in ${EXPIRES_IN}s"
|
||||
|
||||
# Step 2: Use token — expect 200
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
"https://api.example.com/api/protected")
|
||||
[ "$STATUS" = "200" ] && echo "PASS: Valid token accepted" || echo "FAIL: Got $STATUS"
|
||||
|
||||
# Step 3: Use expired/invalid token — expect 401
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: Bearer expired.token.here" \
|
||||
"https://api.example.com/api/protected")
|
||||
[ "$STATUS" = "401" ] && echo "PASS: Expired token rejected" || echo "FAIL: Got $STATUS"
|
||||
|
||||
# Step 4: Missing Authorization header — expect 401
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"https://api.example.com/api/protected")
|
||||
[ "$STATUS" = "401" ] && echo "PASS: No auth rejected" || echo "FAIL: Got $STATUS"
|
||||
|
||||
# Step 5: Malformed header — expect 401
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: NotBearer $ACCESS_TOKEN" \
|
||||
"https://api.example.com/api/protected")
|
||||
[ "$STATUS" = "401" ] && echo "PASS: Bad scheme rejected" || echo "FAIL: Got $STATUS"
|
||||
```
|
||||
|
||||
**Rate limit testing**:
|
||||
```bash
|
||||
# Hit the endpoint rapidly and watch for 429
|
||||
RESULTS_FILE=$(mktemp)
|
||||
for i in $(seq 1 120); do
|
||||
curl -s -o /dev/null -w "%{http_code}\n" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
"https://api.example.com/api/data" >> "$RESULTS_FILE" &
|
||||
done
|
||||
wait
|
||||
|
||||
# Count status codes
|
||||
echo "=== Rate Limit Results ==="
|
||||
sort "$RESULTS_FILE" | uniq -c | sort -rn
|
||||
# Expected: ~100 x 200, ~20 x 429
|
||||
|
||||
# Check rate limit headers on a single request
|
||||
curl -s -D- -o /dev/null \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
"https://api.example.com/api/data" | grep -i "x-ratelimit"
|
||||
# Expected headers:
|
||||
# X-RateLimit-Limit: 100
|
||||
# X-RateLimit-Remaining: 99
|
||||
# X-RateLimit-Reset: 1700000060
|
||||
|
||||
rm "$RESULTS_FILE"
|
||||
```
|
||||
|
||||
**Backoff strategy**: On 429, respect `Retry-After` header. Use exponential backoff (1s, 2s, 4s...) as fallback. Verify the API returns `X-RateLimit-Reset` for client scheduling.
|
||||
|
||||
### Example 3: Testing a Webhook Endpoint
|
||||
|
||||
Scenario: Your API accepts webhook callbacks at `POST /webhooks/payment` with HMAC-SHA256 signature verification.
|
||||
|
||||
**Payload and signature generation**:
|
||||
```bash
|
||||
WEBHOOK_SECRET="whsec_test_secret_key_12345"
|
||||
PAYLOAD='{"event":"payment.completed","data":{"id":"pay_123","amount":4999,"currency":"usd"}}'
|
||||
TIMESTAMP=$(date +%s)
|
||||
SIGNATURE=$(printf "%s.%s" "$TIMESTAMP" "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
|
||||
|
||||
# Valid webhook delivery
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Webhook-Signature: t=$TIMESTAMP,v1=$SIGNATURE" \
|
||||
-H "X-Webhook-Id: wh_evt_001" \
|
||||
-d "$PAYLOAD" \
|
||||
"https://api.example.com/webhooks/payment")
|
||||
[ "$STATUS" = "200" ] || [ "$STATUS" = "204" ] && echo "PASS: Valid webhook accepted" || echo "FAIL: Got $STATUS"
|
||||
```
|
||||
|
||||
**Signature verification tests**:
|
||||
```bash
|
||||
# Wrong signature — expect 401 or 403
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Webhook-Signature: t=$TIMESTAMP,v1=badsignaturevalue" \
|
||||
-d "$PAYLOAD" \
|
||||
"https://api.example.com/webhooks/payment")
|
||||
[ "$STATUS" = "401" ] || [ "$STATUS" = "403" ] && echo "PASS: Bad signature rejected" || echo "FAIL: Got $STATUS"
|
||||
|
||||
# Missing signature header — expect 401
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$PAYLOAD" \
|
||||
"https://api.example.com/webhooks/payment")
|
||||
[ "$STATUS" = "401" ] && echo "PASS: Missing signature rejected" || echo "FAIL: Got $STATUS"
|
||||
|
||||
# Stale timestamp (replay attack) — expect 403
|
||||
OLD_TIMESTAMP=$((TIMESTAMP - 600))
|
||||
OLD_SIGNATURE=$(printf "%s.%s" "$OLD_TIMESTAMP" "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Webhook-Signature: t=$OLD_TIMESTAMP,v1=$OLD_SIGNATURE" \
|
||||
-d "$PAYLOAD" \
|
||||
"https://api.example.com/webhooks/payment")
|
||||
[ "$STATUS" = "403" ] && echo "PASS: Stale timestamp rejected" || echo "FAIL: Got $STATUS"
|
||||
```
|
||||
|
||||
**Also test**: idempotency (same `X-Webhook-Id` sent twice — should be processed once), invalid/empty payloads (expect 400).
|
||||
|
||||
---
|
||||
|
||||
## Authentication Testing Patterns
|
||||
|
||||
### OAuth 2.0 Flow Testing
|
||||
|
||||
**Authorization Code flow**:
|
||||
```bash
|
||||
# Step 1: Initiate authorization — verify redirect
|
||||
AUTHORIZE_URL="https://api.example.com/oauth/authorize?response_type=code&client_id=myapp&redirect_uri=https://myapp.example.com/callback&scope=read+write&state=random_state_123"
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$AUTHORIZE_URL")
|
||||
[ "$STATUS" = "302" ] || [ "$STATUS" = "200" ] && echo "PASS: Auth endpoint reachable" || echo "FAIL: Got $STATUS"
|
||||
|
||||
# Step 2: Exchange authorization code for token
|
||||
TOKEN_RESPONSE=$(curl -s -X POST \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=authorization_code&code=AUTH_CODE_HERE&redirect_uri=https://myapp.example.com/callback&client_id=myapp&client_secret=secret" \
|
||||
"https://api.example.com/oauth/token")
|
||||
echo "$TOKEN_RESPONSE" | python3 -m json.tool
|
||||
# Verify: access_token, refresh_token, expires_in, token_type present
|
||||
|
||||
# Step 3: Use invalid authorization code — expect 400
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=authorization_code&code=INVALID_CODE&redirect_uri=https://myapp.example.com/callback&client_id=myapp&client_secret=secret" \
|
||||
"https://api.example.com/oauth/token")
|
||||
[ "$STATUS" = "400" ] && echo "PASS: Invalid code rejected" || echo "FAIL: Got $STATUS"
|
||||
|
||||
# Step 4: Reuse authorization code — must fail (codes are single-use)
|
||||
# Use the same AUTH_CODE_HERE again
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=authorization_code&code=AUTH_CODE_HERE&redirect_uri=https://myapp.example.com/callback&client_id=myapp&client_secret=secret" \
|
||||
"https://api.example.com/oauth/token")
|
||||
[ "$STATUS" = "400" ] && echo "PASS: Code reuse rejected" || echo "FAIL: Got $STATUS"
|
||||
```
|
||||
|
||||
**Client Credentials flow**: Same pattern as above with `grant_type=client_credentials`. Test: valid credentials (expect `access_token`), invalid secret (expect 401), invalid `grant_type` (expect 400).
|
||||
|
||||
**Refresh Token flow**: Exchange `grant_type=refresh_token` with `refresh_token=$REFRESH_TOKEN`. Verify: new `access_token` returned, old refresh token invalidated if rotation is enabled (reuse should return 400/401).
|
||||
|
||||
### JWT Validation Testing
|
||||
|
||||
Test each type of JWT failure independently:
|
||||
|
||||
| Test Case | Token Modification | Expected Status | Expected Error |
|
||||
|-----------|-------------------|-----------------|----------------|
|
||||
| Expired token | Set `exp` to past timestamp | 401 | `token_expired` |
|
||||
| Not-yet-valid | Set `nbf` to future timestamp | 401 | `token_not_yet_valid` |
|
||||
| Wrong signature | Sign with different key | 401 | `invalid_signature` |
|
||||
| Malformed token | Remove a segment | 401 | `malformed_token` |
|
||||
| Missing `sub` claim | Remove `sub` from payload | 401 | `missing_claims` |
|
||||
| Wrong audience | Set `aud` to different app | 401 | `invalid_audience` |
|
||||
| Wrong issuer | Set `iss` to unknown issuer | 401 | `invalid_issuer` |
|
||||
| Algorithm none attack | Set `alg: none`, remove signature | 401 | `invalid_algorithm` |
|
||||
|
||||
```bash
|
||||
# Generate a test JWT with wrong signature (using python3 as a helper)
|
||||
HEADER=$(echo -n '{"alg":"HS256","typ":"JWT"}' | base64 | tr -d '=' | tr '+/' '-_')
|
||||
PAYLOAD=$(echo -n '{"sub":"user123","exp":9999999999}' | base64 | tr -d '=' | tr '+/' '-_')
|
||||
BAD_SIG=$(echo -n "fakesignature" | base64 | tr -d '=' | tr '+/' '-_')
|
||||
BAD_JWT="${HEADER}.${PAYLOAD}.${BAD_SIG}"
|
||||
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: Bearer $BAD_JWT" \
|
||||
"https://api.example.com/api/protected")
|
||||
[ "$STATUS" = "401" ] && echo "PASS: Bad JWT signature rejected" || echo "FAIL: Got $STATUS"
|
||||
|
||||
# Algorithm "none" attack
|
||||
NONE_HEADER=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr -d '=' | tr '+/' '-_')
|
||||
NONE_JWT="${NONE_HEADER}.${PAYLOAD}."
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: Bearer $NONE_JWT" \
|
||||
"https://api.example.com/api/protected")
|
||||
[ "$STATUS" = "401" ] && echo "PASS: alg:none attack blocked" || echo "FAIL: Got $STATUS — SECURITY RISK"
|
||||
```
|
||||
|
||||
### API Key Testing Patterns
|
||||
|
||||
```bash
|
||||
# Valid API key in header
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "X-API-Key: valid_key_abc123" \
|
||||
"https://api.example.com/api/data")
|
||||
[ "$STATUS" = "200" ] && echo "PASS: Valid API key" || echo "FAIL: Got $STATUS"
|
||||
```
|
||||
|
||||
**Also test**: key in query param (if supported), revoked key (expect 401/403), empty key (expect 401), read-only key attempting write (expect 403).
|
||||
|
||||
### Session-Based Auth Testing
|
||||
|
||||
Test pattern: login (capture `Set-Cookie`), use cookie for authenticated request (expect 200), logout, reuse cookie (expect 401). Also verify session fixation prevention — session ID should rotate on login.
|
||||
|
||||
---
|
||||
|
||||
## Contract Testing
|
||||
|
||||
### Schema Validation Techniques
|
||||
|
||||
Validate API responses against a JSON Schema using `python3 -c "from jsonschema import validate; ..."`:
|
||||
|
||||
```bash
|
||||
# Fetch response and validate against schema file
|
||||
curl -s -H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/users/user_001" | python3 -c "
|
||||
import sys, json
|
||||
from jsonschema import validate, ValidationError
|
||||
schema = json.load(open('/tmp/user_schema.json'))
|
||||
try:
|
||||
validate(instance=json.load(sys.stdin), schema=schema)
|
||||
print('PASS: Schema valid')
|
||||
except ValidationError as e:
|
||||
print(f'FAIL: {e.message}')
|
||||
"
|
||||
```
|
||||
|
||||
Schema should define `required` fields, property `type`/`format`/`enum` constraints, and `additionalProperties: false` for strict mode.
|
||||
|
||||
### Breaking Change Detection
|
||||
|
||||
Compare current response structure against a recorded baseline:
|
||||
|
||||
```bash
|
||||
# Helper: extract JSON shape as "path: type" lines
|
||||
extract_shape() {
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "$1" | python3 -c "
|
||||
import sys, json
|
||||
def shape(obj, prefix=''):
|
||||
s = {}
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
p = f'{prefix}.{k}' if prefix else k
|
||||
s[p] = type(v).__name__; s.update(shape(v, p))
|
||||
elif isinstance(obj, list) and obj:
|
||||
s[f'{prefix}[]'] = type(obj[0]).__name__; s.update(shape(obj[0], f'{prefix}[]'))
|
||||
return s
|
||||
for p, t in sorted(shape(json.load(sys.stdin)).items()): print(f'{p}: {t}')
|
||||
"
|
||||
}
|
||||
|
||||
# Record baseline once, then diff against current
|
||||
extract_shape "https://api.example.com/api/users/user_001" > /tmp/api_baseline.txt
|
||||
# ... later ...
|
||||
extract_shape "https://api.example.com/api/users/user_001" > /tmp/api_current.txt
|
||||
diff /tmp/api_baseline.txt /tmp/api_current.txt && echo "PASS: No schema changes" || echo "WARN: Schema changed"
|
||||
```
|
||||
|
||||
### Backward Compatibility Checklist
|
||||
|
||||
When a new API version is deployed, verify that existing consumers are not broken:
|
||||
|
||||
| Check | How to Test | Severity |
|
||||
|-------|------------|----------|
|
||||
| Removed fields | Diff response shape against baseline | **HIGH** — breaks consumers |
|
||||
| Renamed fields | Diff response keys | **HIGH** — breaks consumers |
|
||||
| Changed field type | Compare type of each field | **HIGH** — breaks deserialization |
|
||||
| New required request field | Send old-format request | **HIGH** — breaks callers |
|
||||
| Changed enum values | Check if old values still accepted | **MEDIUM** — breaks validation |
|
||||
| Changed error format | Compare error response structure | **MEDIUM** — breaks error handlers |
|
||||
| Changed status codes | Compare response codes for same input | **MEDIUM** — breaks status checks |
|
||||
| New optional fields | Verify response still parses | **LOW** — usually safe |
|
||||
| Pagination format change | Test with existing page params | **MEDIUM** — breaks pagination loops |
|
||||
|
||||
### Consumer-Driven Contract Testing
|
||||
|
||||
Concept: Each API consumer defines the minimum contract they need (required fields, forbidden fields, expected status codes). The provider runs all consumer contracts in CI.
|
||||
|
||||
```json
|
||||
{
|
||||
"consumer": "mobile-app-v2",
|
||||
"provider": "user-service",
|
||||
"interactions": [
|
||||
{
|
||||
"description": "get user profile",
|
||||
"request": {"method": "GET", "path": "/api/users/me", "headers": {"Authorization": "Bearer valid_token"}},
|
||||
"response": {"status": 200, "body_contains": ["id", "name", "email"], "body_must_not_contain": ["password", "internal_id"]}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Runner approach: iterate interactions, execute each request with curl, verify status code matches and required/forbidden fields are present/absent in the response body.
|
||||
|
||||
---
|
||||
|
||||
## Performance Testing Deep Dive
|
||||
|
||||
### Load Test Types
|
||||
|
||||
| Type | Purpose | Pattern |
|
||||
|------|---------|---------|
|
||||
| **Soak** | Detect memory leaks, connection pool exhaustion | Steady traffic (e.g., 5 req/s) for hours; compare first-quarter vs last-quarter response times |
|
||||
| **Spike** | Verify graceful handling of sudden bursts | Baseline → 10x-20x burst → recovery; check error rate and recovery time |
|
||||
| **Stress** | Find the breaking point | Incrementally increase concurrency until errors begin |
|
||||
|
||||
### Stress Testing (Representative Example)
|
||||
|
||||
Incrementally increase load until errors begin — adapt the same pattern for soak (fixed concurrency, long duration) or spike (sudden burst) testing:
|
||||
|
||||
```bash
|
||||
echo "concurrency,success_rate,avg_time,p95_time" > /tmp/stress_results.csv
|
||||
for CONCURRENCY in 10 25 50 100 200 500; do
|
||||
RESULTS=$(mktemp)
|
||||
for i in $(seq 1 $CONCURRENCY); do
|
||||
curl -s -o /dev/null -w "%{http_code} %{time_total}\n" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/data" >> "$RESULTS" &
|
||||
done
|
||||
wait
|
||||
|
||||
TOTAL=$(wc -l < "$RESULTS")
|
||||
SUCCESS=$(grep -c "^200" "$RESULTS")
|
||||
AVG_TIME=$(awk '{sum+=$2; n++} END {printf "%.3f", sum/n}' "$RESULTS")
|
||||
P95_TIME=$(awk '{print $2}' "$RESULTS" | sort -n | awk -v p=0.95 'NR==1{n=0} {a[n++]=$1} END {print a[int(n*p)]}')
|
||||
|
||||
echo "$CONCURRENCY,$((SUCCESS*100/TOTAL))%,$AVG_TIME,$P95_TIME" >> /tmp/stress_results.csv
|
||||
echo "Concurrency $CONCURRENCY: ${SUCCESS}/${TOTAL} success, avg=${AVG_TIME}s, p95=${P95_TIME}s"
|
||||
|
||||
rm "$RESULTS"
|
||||
sleep 3 # Let the server recover between steps
|
||||
done
|
||||
|
||||
echo "=== Stress Test Summary ==="
|
||||
column -t -s',' /tmp/stress_results.csv
|
||||
```
|
||||
|
||||
### Latency Percentile Analysis
|
||||
|
||||
Collect many response times (e.g., 1000 with concurrency capped at 20), then compute p50/p75/p90/p95/p99 percentiles. Compare first-quarter vs last-quarter averages to detect degradation over time.
|
||||
|
||||
```bash
|
||||
# Collect response times
|
||||
TIMES_FILE=$(mktemp)
|
||||
for i in $(seq 1 1000); do
|
||||
curl -s -o /dev/null -w "%{time_total}\n" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/data" >> "$TIMES_FILE" &
|
||||
[ $((i % 20)) -eq 0 ] && wait
|
||||
done
|
||||
wait
|
||||
# Sort and compute percentiles with: sort -n "$TIMES_FILE" | python3 ...
|
||||
rm "$TIMES_FILE"
|
||||
```
|
||||
|
||||
### Connection Pool Testing
|
||||
|
||||
- **Keep-alive reuse**: Send multiple URLs in one curl call with `Connection: keep-alive`; second/third requests should show near-zero `time_connect`.
|
||||
- **Connection exhaustion**: Open 500 concurrent keep-alive connections; watch for 503 or connection refused errors.
|
||||
|
||||
---
|
||||
|
||||
## Common API Bugs & How to Find Them
|
||||
|
||||
### N+1 Query Detection
|
||||
|
||||
Response time should not scale linearly with data size. If fetching 10 items takes 100ms but 100 items takes 1000ms, the API likely has an N+1 query problem.
|
||||
|
||||
```bash
|
||||
# Compare response times for different page sizes
|
||||
for SIZE in 1 10 50 100; do
|
||||
TIME=$(curl -s -o /dev/null -w "%{time_total}" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/orders?per_page=$SIZE")
|
||||
echo "page_size=$SIZE time=${TIME}s"
|
||||
done
|
||||
# Expected (healthy): Times should NOT scale linearly
|
||||
# page_size=1 time=0.045s
|
||||
# page_size=10 time=0.052s
|
||||
# page_size=50 time=0.078s
|
||||
# page_size=100 time=0.110s
|
||||
# Red flag (N+1): Times scale roughly linearly
|
||||
# page_size=1 time=0.045s
|
||||
# page_size=10 time=0.350s
|
||||
# page_size=50 time=1.600s
|
||||
# page_size=100 time=3.200s
|
||||
```
|
||||
|
||||
### Race Condition Testing
|
||||
|
||||
```bash
|
||||
# Concurrent counter increment — final value should equal attempt count
|
||||
curl -s -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"value": 0}' "https://api.example.com/api/counters/counter_001"
|
||||
|
||||
for i in $(seq 1 50); do
|
||||
curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"increment": 1}' "https://api.example.com/api/counters/counter_001/increment" &
|
||||
done
|
||||
wait
|
||||
|
||||
FINAL=$(curl -s -H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/counters/counter_001" | python3 -c "import sys,json; print(json.load(sys.stdin)['value'])")
|
||||
[ "$FINAL" = "50" ] && echo "PASS: No race condition" || echo "FAIL: Lost $((50 - FINAL)) increments"
|
||||
```
|
||||
|
||||
**Optimistic locking test**: Two concurrent PUTs with same `If-Match` ETag — one should get 200, the other 409 Conflict.
|
||||
|
||||
### Pagination Edge Cases
|
||||
|
||||
| Input | Expected Behavior |
|
||||
|-------|------------------|
|
||||
| `page=0` | 400, or treat as page 1 |
|
||||
| `page=-1` | 400 |
|
||||
| `page=99999` (beyond data) | 200 with empty array, not error |
|
||||
| `per_page=0` | 400 or use default |
|
||||
| `per_page=100000` | Capped to server max (e.g., 100) |
|
||||
| Delete item mid-pagination | No items skipped or duplicated on next page |
|
||||
|
||||
### Timezone Handling Bugs
|
||||
|
||||
Test that equivalent timestamps in different offset formats are stored identically:
|
||||
|
||||
```bash
|
||||
# All four represent the same moment — stored values should be equivalent
|
||||
for TZ in "2025-06-15T10:00:00Z" "2025-06-15T10:00:00+00:00" "2025-06-15T18:00:00+08:00" "2025-06-15T05:00:00-05:00"; do
|
||||
STORED=$(curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
|
||||
-d "{\"title\": \"tz_test\", \"scheduled_at\": \"$TZ\"}" \
|
||||
"https://api.example.com/api/events" | python3 -c "import sys,json; print(json.load(sys.stdin).get('scheduled_at','ERROR'))")
|
||||
echo "Input: $TZ -> Stored: $STORED"
|
||||
done
|
||||
```
|
||||
|
||||
**Also test**: date range filters across timezone boundaries, midnight boundary inclusion/exclusion behavior.
|
||||
|
||||
### Character Encoding Issues
|
||||
|
||||
Test that the API correctly round-trips various Unicode inputs. Key test values:
|
||||
|
||||
| Category | Example | What Breaks |
|
||||
|----------|---------|-------------|
|
||||
| Emoji | `Hello 🌍🚀` | UTF-8 4-byte sequences, database column width |
|
||||
| CJK | `你好世界` | Multi-byte encoding, string length vs byte length |
|
||||
| Diacritics | `café` (composed vs decomposed) | Unicode normalization (NFC vs NFD) |
|
||||
| Zero-width | `test\u200Bword` | Invisible characters in search/comparison |
|
||||
| Null byte | `test\u0000value` | String termination in C-based systems |
|
||||
|
||||
```bash
|
||||
# Round-trip test pattern: POST a value, verify GET returns the same
|
||||
for VALUE in "Hello 🌍🚀" "你好世界" "café"; do
|
||||
RESPONSE=$(curl -s -X POST -H "Content-Type: application/json; charset=utf-8" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d "{\"name\": \"$VALUE\"}" \
|
||||
"https://api.example.com/api/items")
|
||||
RETURNED=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('name','ERROR'))")
|
||||
[ "$VALUE" = "$RETURNED" ] && echo "PASS: $VALUE" || echo "FAIL: sent='$VALUE' got='$RETURNED'"
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced curl Patterns
|
||||
|
||||
### File Upload Testing
|
||||
|
||||
```bash
|
||||
# Single file upload
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-F "file=@/path/to/document.pdf" \
|
||||
-F "description=Test upload" \
|
||||
"https://api.example.com/api/uploads")
|
||||
echo "Single file upload: $STATUS"
|
||||
|
||||
# Multiple file upload
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-F "files[]=@/path/to/file1.png" \
|
||||
-F "files[]=@/path/to/file2.png" \
|
||||
-F "category=images" \
|
||||
"https://api.example.com/api/uploads/batch")
|
||||
echo "Multi-file upload: $STATUS"
|
||||
```
|
||||
|
||||
**Edge cases to also test**: oversized files (expect 413), wrong content type (e.g., `script.sh` declared as `image/png`), zero-byte files (expect 400).
|
||||
|
||||
### Multipart Form Data
|
||||
|
||||
```bash
|
||||
# Mixed multipart: file + JSON metadata
|
||||
curl -s -X POST \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-F "metadata={\"title\":\"Report Q4\",\"tags\":[\"finance\",\"quarterly\"]};type=application/json" \
|
||||
-F "file=@/path/to/report.pdf" \
|
||||
"https://api.example.com/api/documents"
|
||||
|
||||
# Form-encoded data (not JSON)
|
||||
curl -s -X POST \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "username=testuser&password=testpass&remember=true" \
|
||||
"https://api.example.com/auth/login"
|
||||
```
|
||||
|
||||
### Cookie-Based Session Testing
|
||||
|
||||
```bash
|
||||
# Full session lifecycle with cookie jar
|
||||
COOKIE_JAR=$(mktemp)
|
||||
|
||||
# Login — store cookies
|
||||
curl -s -c "$COOKIE_JAR" -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username": "testuser", "password": "testpass"}' \
|
||||
"https://api.example.com/auth/login"
|
||||
|
||||
# Authenticated request — send cookies
|
||||
curl -s -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
|
||||
"https://api.example.com/api/profile"
|
||||
|
||||
# Logout and verify session invalidated
|
||||
curl -s -b "$COOKIE_JAR" -c "$COOKIE_JAR" -X POST \
|
||||
"https://api.example.com/auth/logout"
|
||||
STATUS=$(curl -s -b "$COOKIE_JAR" -o /dev/null -w "%{http_code}" \
|
||||
"https://api.example.com/api/profile")
|
||||
[ "$STATUS" = "401" ] && echo "PASS: Session invalidated" || echo "FAIL: Got $STATUS"
|
||||
rm "$COOKIE_JAR"
|
||||
```
|
||||
|
||||
**Also verify**: HttpOnly/Secure/SameSite cookie attributes, session ID rotation on login (session fixation prevention).
|
||||
|
||||
### Following Redirects
|
||||
|
||||
```bash
|
||||
# Follow redirects automatically
|
||||
curl -s -L -o /dev/null -w "final_url:%{url_effective} status:%{http_code} redirects:%{num_redirects}\n" \
|
||||
"https://api.example.com/old-endpoint"
|
||||
|
||||
# Don't follow — inspect redirect target
|
||||
curl -s -D- -o /dev/null \
|
||||
"https://api.example.com/old-endpoint" | grep -i "location:"
|
||||
|
||||
# Open redirect vulnerability test
|
||||
LOCATION=$(curl -s -D- -o /dev/null \
|
||||
"https://api.example.com/redirect?url=https://evil.example.com" | grep -i "location:" | tr -d '\r')
|
||||
echo "$LOCATION" | grep -q "evil.example.com" && echo "FAIL: Open redirect vulnerability" || echo "PASS: Redirect restricted"
|
||||
|
||||
# HTTP to HTTPS redirect check
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://api.example.com/api/data")
|
||||
[ "$STATUS" = "301" ] || [ "$STATUS" = "308" ] && echo "PASS: HTTP redirects to HTTPS" || echo "WARN: No HTTPS redirect (got $STATUS)"
|
||||
```
|
||||
|
||||
### HEAD, OPTIONS, and CORS
|
||||
|
||||
```bash
|
||||
# HEAD request — verify no body returned
|
||||
curl -s -I -w "status:%{http_code} size:%{size_download}\n" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.example.com/api/data"
|
||||
|
||||
# OPTIONS request — check CORS and allowed methods
|
||||
curl -s -X OPTIONS -D- -o /dev/null \
|
||||
-H "Origin: https://myapp.example.com" \
|
||||
-H "Access-Control-Request-Method: POST" \
|
||||
"https://api.example.com/api/data" | grep -iE "(allow|access-control)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chaos & Fault Injection Patterns
|
||||
|
||||
| Fault | How to Inject | Expected Behavior |
|
||||
|-------|--------------|-------------------|
|
||||
| Slow client | `curl --limit-rate 1k` | Server does not hold connection indefinitely; times out gracefully |
|
||||
| Partial body | Pipe truncated JSON via `echo '{"name":' \| curl -d @-` | 400 Bad Request, not 500 |
|
||||
| Huge header | `-H "X-Pad: $(python3 -c 'print("A"*16000)')"` | 431 Request Header Fields Too Large or 400 |
|
||||
| Concurrent duplicate | Fire same POST with idempotency key 50x in parallel | Exactly one resource created; others get 409 or identical response |
|
||||
| Connection reset | `curl --max-time 0.001` (client aborts mid-response) | Server logs show no crash; subsequent requests succeed |
|
||||
| Malformed encoding | Send `Content-Type: application/json; charset=iso-8859-1` with UTF-8 body | API rejects or correctly transcodes; no mojibake in stored data |
|
||||
|
||||
---
|
||||
|
||||
## API Versioning Test Strategies
|
||||
|
||||
When an API exposes multiple versions, verify isolation and deprecation handling:
|
||||
|
||||
| Test | Method | Expected |
|
||||
|------|--------|----------|
|
||||
| Old version still works | `GET /api/v1/resource` | 200 with v1 schema (or 410 if sunset) |
|
||||
| New version returns new schema | `GET /api/v2/resource` | 200 with v2 fields present |
|
||||
| Version via header | `Accept: application/vnd.api.v2+json` | Response matches v2 schema |
|
||||
| Unsupported version | `GET /api/v99/resource` | 404 or 400, not fallback to latest |
|
||||
| Sunset header | Check `Sunset:` and `Deprecation:` headers on old versions | Headers present with valid dates |
|
||||
| Cross-version mutation | Create in v1, read in v2 and vice versa | Data accessible in both; fields map correctly |
|
||||
|
||||
---
|
||||
|
||||
## GraphQL-Specific Testing Patterns
|
||||
|
||||
When the target exposes a GraphQL endpoint (`POST /graphql`):
|
||||
|
||||
- **Introspection**: Send `{ __schema { types { name } } }` — should be disabled in production (expect error), or return schema if intentionally public
|
||||
- **Query depth attack**: Nest a query 15+ levels deep (e.g. `{ user { friends { friends { ... } } } }`) — expect a depth-limit error, not a timeout
|
||||
- **Batch attack**: Send an array of 100 queries in one request — expect rejection or rate limiting, not 100x execution cost
|
||||
- **Field suggestion leak**: Send a query with a typo (e.g. `{ usr { name } }`) — verify the error does not suggest valid field names in production
|
||||
- **Alias-based DoS**: Query the same expensive field 50 times using aliases (`a1: expensiveField, a2: expensiveField, ...`) — expect query complexity rejection
|
||||
- **Mutation authorization**: Execute mutations for other users' resources — expect authorization errors identical to REST BOLA checks
|
||||
- **N+1 detection**: Query a list with nested relations (`{ users { orders { items } } }`) — linear response time scaling signals N+1
|
||||
|
||||
---
|
||||
|
||||
## Webhook Reliability Testing Patterns
|
||||
|
||||
Beyond signature verification (covered in worked examples), test delivery reliability:
|
||||
|
||||
| Scenario | How to Simulate | What to Verify |
|
||||
|----------|----------------|----------------|
|
||||
| Slow consumer | Respond with 200 after 25s delay | Sender respects timeout >30s; does not mark as failed prematurely |
|
||||
| Consumer down | Return 503 for first 3 deliveries | Sender retries with exponential backoff; check `X-Retry-Count` |
|
||||
| Duplicate delivery | Verify same `X-Webhook-Id` arrives twice | Consumer handles idempotently — no duplicate side effects |
|
||||
| Out-of-order events | Process events t2 before t1 | Consumer uses event timestamp, not arrival order, for state |
|
||||
| Oversized payload | Trigger event producing >1MB payload | Sender truncates or sends reference URL instead of inline data |
|
||||
| Replay attack | Accept delivery with timestamp >5min old | Consumer rejects stale deliveries to prevent replay |
|
||||
+401
-74
@@ -142,6 +142,59 @@ description = "Automatically take a screenshot after every click/navigate for vi
|
||||
setting_type = "toggle"
|
||||
default = "false"
|
||||
|
||||
[[settings]]
|
||||
key = "cookie_persistence"
|
||||
label = "Cookie Persistence"
|
||||
description = "Persist cookies across tasks in the same session to maintain login state and preferences"
|
||||
setting_type = "toggle"
|
||||
default = "true"
|
||||
|
||||
[[settings]]
|
||||
key = "user_agent"
|
||||
label = "User Agent"
|
||||
description = "Browser user-agent string sent with requests — affects how websites identify the browser"
|
||||
setting_type = "select"
|
||||
default = "chrome_desktop"
|
||||
|
||||
[[settings.options]]
|
||||
value = "chrome_desktop"
|
||||
label = "Chrome Desktop (most compatible)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "firefox_desktop"
|
||||
label = "Firefox Desktop"
|
||||
|
||||
[[settings.options]]
|
||||
value = "chrome_mobile"
|
||||
label = "Chrome Mobile (Android)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "safari_mobile"
|
||||
label = "Safari Mobile (iOS)"
|
||||
|
||||
[[settings]]
|
||||
key = "viewport_size"
|
||||
label = "Viewport Size"
|
||||
description = "Browser window dimensions — affects responsive layout and which version of a site is served"
|
||||
setting_type = "select"
|
||||
default = "1920x1080"
|
||||
|
||||
[[settings.options]]
|
||||
value = "1920x1080"
|
||||
label = "1920x1080 (Full HD desktop)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "1366x768"
|
||||
label = "1366x768 (Laptop)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "390x844"
|
||||
label = "390x844 (Mobile)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "1024x768"
|
||||
label = "1024x768 (Tablet)"
|
||||
|
||||
# ─── Agent configuration ─────────────────────────────────────────────────────
|
||||
|
||||
[agent]
|
||||
@@ -157,114 +210,153 @@ system_prompt = """You are Browser Hand — an autonomous web browser agent that
|
||||
|
||||
## Core Capabilities
|
||||
|
||||
You can navigate to URLs, click buttons/links, fill forms, read page content, and take screenshots. You have a real browser session that persists across tool calls within a conversation.
|
||||
You can navigate to URLs, click buttons/links, fill forms, read page content, and take screenshots. You have a real browser session that persists across tool calls within a conversation. Cookies and login state carry over between actions unless the session is explicitly closed.
|
||||
|
||||
## Multi-Phase Pipeline
|
||||
|
||||
### Phase 1 — Understand the Task
|
||||
Parse the user's request and plan your approach:
|
||||
### Phase 1 — Understand & Plan
|
||||
Parse the user's request and build an execution plan:
|
||||
- What website(s) do you need to visit?
|
||||
- What information do you need to find or what action do you need to perform?
|
||||
- What are the success criteria?
|
||||
- Is the target likely a SPA (single-page app) or a traditional server-rendered site?
|
||||
- Will login or cookie consent be needed before reaching the goal?
|
||||
|
||||
### Phase 2 — Navigate & Observe
|
||||
1. Use `browser_navigate` to go to the target URL
|
||||
2. Read the page content to understand the layout
|
||||
3. Identify the relevant elements (buttons, links, forms, search boxes)
|
||||
2. Use `browser_read_page` to understand the page structure
|
||||
3. Identify page type: static HTML, SPA framework, or hybrid
|
||||
4. Handle blocking overlays immediately (cookie banners, modals, age gates)
|
||||
5. Verify you are on the correct domain and the page loaded completely
|
||||
6. If content appears empty or minimal, wait 3-5 seconds and re-read — SPAs often render asynchronously
|
||||
|
||||
### Phase 3 — Interact
|
||||
1. Use `browser_click` for buttons and links (use CSS selectors or visible text)
|
||||
### Phase 3 — Detect & Adapt to Page Technology
|
||||
Detect the page technology to choose the right interaction strategy:
|
||||
|
||||
**SPA detection signals** (any of these means client-side rendering):
|
||||
- Page has a single `<div id="root">` or `<div id="app">` with most content nested inside
|
||||
- URL changes do not trigger full page reloads (hash routes like `#/page` or history API routes)
|
||||
- Content appears after a delay with loading spinners or skeleton screens
|
||||
- Page source is minimal HTML with large JS bundles
|
||||
|
||||
**SPA interaction rules:**
|
||||
- After every click that changes the view, wait 1-3 seconds before reading the page
|
||||
- Look for loading indicators: `[aria-busy="true"]`, `.loading`, `.spinner`, `.skeleton`
|
||||
- If `browser_read_page` returns stale content, wait and retry (up to 3 attempts)
|
||||
- Prefer clicking visible UI elements over direct URL navigation (SPAs may not support deep links)
|
||||
|
||||
**Iframe handling:**
|
||||
- If target content is inside an iframe, note that `browser_read_page` may not capture iframe contents
|
||||
- Try navigating directly to the iframe's `src` URL if you need to interact with its content
|
||||
- For embedded widgets (payment forms, third-party logins), inform the user if interaction is blocked
|
||||
|
||||
**Shadow DOM:**
|
||||
- Some web components use shadow DOM which hides elements from normal selectors
|
||||
- If a known element is not found, it may be inside a shadow root
|
||||
- Use `browser_screenshot` to visually confirm the element exists, then try interacting by visible text
|
||||
|
||||
### Phase 4 — Interact & Verify
|
||||
1. Use `browser_click` for buttons and links — prefer these selector strategies in order:
|
||||
a. `[data-testid="..."]` or `[data-test="..."]` — most stable, survives UI redesigns
|
||||
b. `[aria-label="..."]` or `[role="button"]` — accessibility-based, framework-independent
|
||||
c. `#id` — unique but may be auto-generated in SPAs
|
||||
d. Visible text content — reliable fallback when selectors fail
|
||||
e. CSS class selectors — least stable, use only as last resort
|
||||
2. Use `browser_type` for filling form fields
|
||||
3. Use `browser_read_page` after each action to see the updated state
|
||||
4. Use `browser_screenshot` when you need visual verification
|
||||
3. Use `browser_read_page` after each action to verify the expected state change occurred
|
||||
4. Use `browser_screenshot` when text content alone is ambiguous or for visual verification
|
||||
5. If an action produces no visible change, check for overlays, disabled states, or incomplete page loads before retrying
|
||||
|
||||
### Phase 4 — MANDATORY Purchase/Payment Approval
|
||||
### Phase 5 — Error Recovery & Retry
|
||||
When an interaction fails, follow this decision tree:
|
||||
|
||||
1. **Element not found:**
|
||||
a. Re-read the page — DOM may have changed since last read
|
||||
b. Try alternative selectors: data-testid > aria-label > role > visible text > class
|
||||
c. Scroll the page to trigger lazy loading, then re-read
|
||||
d. Take a screenshot to see the actual page state
|
||||
e. If still not found after 3 attempts, report to user with what was tried
|
||||
|
||||
2. **Click has no effect:**
|
||||
a. Check for overlays blocking the element (cookie banners, modals, chat widgets)
|
||||
b. Dismiss overlays: look for "Accept", "Close", "X", or `[aria-label="Close"]` buttons
|
||||
c. Check if the element is disabled (`[disabled]`, `[aria-disabled="true"]`, `.disabled`)
|
||||
d. Try clicking a more specific child element (e.g., the `<span>` inside a `<button>`)
|
||||
e. Wait 2 seconds and retry — JavaScript handlers may not have attached yet
|
||||
|
||||
3. **Navigation failure or timeout:**
|
||||
a. Retry the same URL once
|
||||
b. Try the base domain URL, then navigate to the target from there
|
||||
c. Check for redirect loops — read current URL and compare to expected
|
||||
d. If 429/rate-limited: wait 30 seconds, then retry with longer intervals
|
||||
e. If 403/blocked: inform user that the site may be blocking automated access
|
||||
|
||||
4. **Session/auth expired mid-task:**
|
||||
a. Detect by checking if redirected to a login page unexpectedly
|
||||
b. Re-authenticate using previously provided credentials (never store passwords in memory)
|
||||
c. After re-login, navigate back to where you left off
|
||||
d. If re-login fails, inform user
|
||||
|
||||
5. **CAPTCHA encountered:**
|
||||
a. Take a screenshot to show the user
|
||||
b. Inform user that manual intervention is needed — you cannot solve CAPTCHAs
|
||||
c. Wait for user input before continuing
|
||||
|
||||
### Phase 6 — MANDATORY Purchase/Payment Approval
|
||||
**CRITICAL RULE**: Before completing ANY purchase, payment, or form submission that involves money:
|
||||
1. Summarize what you are about to buy/pay for
|
||||
2. Show the total cost
|
||||
3. List all items in the cart
|
||||
2. Show the total cost including taxes and shipping
|
||||
3. List all items in the cart with quantities
|
||||
4. STOP and ask the user for explicit confirmation
|
||||
5. Only proceed after receiving clear approval
|
||||
|
||||
NEVER auto-complete purchases. NEVER click "Place Order", "Pay Now", "Confirm Purchase", or any payment button without user approval.
|
||||
|
||||
### Phase 5 — Report Results
|
||||
### Phase 7 — Report & Persist
|
||||
After completing the task:
|
||||
1. Summarize what was accomplished
|
||||
2. Include relevant details (prices, confirmation numbers, etc.)
|
||||
1. Summarize what was accomplished with relevant details (prices, confirmation numbers, URLs)
|
||||
2. If the task involved comparison or research, present findings in a structured format
|
||||
3. Save important data to memory for future reference
|
||||
4. Close browser tabs that are no longer needed to free resources
|
||||
|
||||
## CSS Selector Cheat Sheet
|
||||
## Selector Strategy (Priority Order)
|
||||
|
||||
Common selectors for web interaction:
|
||||
- `#id` — element by ID (e.g., `#search-box`, `#add-to-cart`)
|
||||
- `.class` — element by class (e.g., `.btn-primary`, `.product-title`)
|
||||
- `input[name="email"]` — input by name attribute
|
||||
- `input[type="search"]` — search inputs
|
||||
- `button[type="submit"]` — submit buttons
|
||||
- `a[href*="cart"]` — links containing "cart" in href
|
||||
- `[data-testid="checkout"]` — elements with test IDs
|
||||
- `select[name="quantity"]` — dropdown selectors
|
||||
Always prefer stable selectors over fragile ones. Try in this order:
|
||||
1. `[data-testid="value"]` — explicitly added for testing, rarely changes
|
||||
2. `[aria-label="value"]` — accessibility attributes, semantic and stable
|
||||
3. `[role="button"]`, `[role="link"]`, `[role="textbox"]` — ARIA roles
|
||||
4. `#id` — unique identifiers (but beware auto-generated IDs like `#react-select-2-input`)
|
||||
5. `input[name="field"]`, `input[type="email"]` — form semantics
|
||||
6. Visible text content — human-readable, works across frameworks
|
||||
7. `.class-name` — least stable, especially in SPA frameworks that generate class names
|
||||
|
||||
When CSS selectors fail, fall back to clicking by visible text content.
|
||||
## Popup & Modal Dismissal
|
||||
|
||||
## Common Web Interaction Patterns
|
||||
Handle these immediately when they appear, before attempting any other interaction:
|
||||
1. **Cookie consent**: "Accept All", "Agree", `#onetrust-accept-btn-handler`, `.cookie-consent .accept`
|
||||
2. **Newsletter/promo modals**: `.modal .close`, `[aria-label="Close"]`, `button.dismiss`, Escape key
|
||||
3. **Chat widgets**: minimize or close if they overlap target elements
|
||||
4. **Age verification**: click "Yes" / "I am over 18" / "Enter"
|
||||
5. **App install banners**: dismiss or click "Continue in browser"
|
||||
6. **Notification permission prompts**: auto-dismissed by Playwright context settings
|
||||
|
||||
### Search Pattern
|
||||
1. Navigate to site
|
||||
2. Find search box: `input[type="search"]`, `input[name="q"]`, `#search`
|
||||
3. Type query with `browser_type`
|
||||
4. Click search button or the text will auto-submit
|
||||
5. Read results
|
||||
## Cookie & Session Handling
|
||||
|
||||
### Login Pattern
|
||||
1. Navigate to login page
|
||||
2. Fill email/username: `input[name="email"]` or `input[type="email"]`
|
||||
3. Fill password: `input[name="password"]` or `input[type="password"]`
|
||||
4. Click login button: `button[type="submit"]`, `.login-btn`
|
||||
5. Verify login success by reading page
|
||||
|
||||
### E-commerce Pattern
|
||||
1. Search for product
|
||||
2. Click product from results
|
||||
3. Select options (size, color, quantity)
|
||||
4. Click "Add to Cart"
|
||||
5. Navigate to cart
|
||||
6. Review items and total
|
||||
7. **STOP — Ask user for purchase approval**
|
||||
8. Only proceed to checkout after approval
|
||||
|
||||
### Form Filling Pattern
|
||||
1. Navigate to form page
|
||||
2. Read form structure
|
||||
3. Fill fields one by one with `browser_type`
|
||||
4. Use `browser_click` for checkboxes, radio buttons, dropdowns
|
||||
5. Screenshot before submission for verification
|
||||
6. Submit form
|
||||
|
||||
## Error Recovery
|
||||
|
||||
- If a click fails, try a different selector or use visible text
|
||||
- If a page doesn't load, wait and retry with `browser_navigate`
|
||||
- If you get a CAPTCHA, inform the user — you cannot solve CAPTCHAs
|
||||
- If a login is required, ask the user for credentials (never store passwords)
|
||||
- If blocked or rate-limited, wait and try again, or inform the user
|
||||
- Your browser session persists cookies across messages in this conversation
|
||||
- After login, verify session is active before sensitive operations by reading a protected page
|
||||
- If a page unexpectedly shows a login form, the session has expired — re-authenticate
|
||||
- When navigating across subdomains (e.g., shop.example.com to account.example.com), verify cookies carried over
|
||||
- Use `browser_close` when done to free resources; the browser auto-closes when the conversation ends
|
||||
|
||||
## Security Rules
|
||||
|
||||
- NEVER store passwords or credit card numbers in memory
|
||||
- NEVER auto-complete payments without user approval
|
||||
- NEVER navigate to URLs from untrusted sources without checking them
|
||||
- NEVER navigate to URLs from untrusted sources without verifying the domain
|
||||
- NEVER fill in credentials without the user explicitly providing them
|
||||
- Always verify the domain matches the expected site before entering sensitive data (watch for typosquatting)
|
||||
- If you encounter suspicious or phishing-like content, warn the user immediately
|
||||
- Always verify you're on the correct domain before entering sensitive information
|
||||
|
||||
## Session Management
|
||||
|
||||
- Your browser session persists across messages in this conversation
|
||||
- Cookies and login state are maintained
|
||||
- Use `browser_close` when you're done to free resources
|
||||
- The browser auto-closes when the conversation ends
|
||||
- Never enter credentials on HTTP (non-HTTPS) pages
|
||||
|
||||
Update stats via memory_store after each task:
|
||||
- `browser_hand_pages_visited` — increment by pages navigated
|
||||
@@ -296,6 +388,241 @@ token_consumption = "low"
|
||||
default_active = true
|
||||
activation_warning = "Browser hand runs continuously but mainly consumes tokens when actively performing web tasks."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "浏览器 Hand"
|
||||
description = "自主网页浏览器——导航网站、填写表单、点击按钮,经用户批准后完成多步骤网页任务"
|
||||
category = "生产力"
|
||||
|
||||
[i18n.zh.settings.headless]
|
||||
label = "无头模式"
|
||||
description = "在不显示浏览器窗口的情况下运行(推荐用于服务器环境)"
|
||||
|
||||
[i18n.zh.settings.approval_mode]
|
||||
label = "购买审批"
|
||||
description = "在完成任何购买或支付操作前,需要用户明确确认"
|
||||
|
||||
[i18n.zh.settings.max_pages_per_task]
|
||||
label = "每任务最大页面数"
|
||||
description = "每个任务允许的最大页面导航次数,防止无限浏览"
|
||||
|
||||
[i18n.zh.settings.default_wait]
|
||||
label = "操作后默认等待"
|
||||
description = "点击或导航后等待页面稳定的时长"
|
||||
|
||||
[i18n.zh.settings.screenshot_on_action]
|
||||
label = "操作后截图"
|
||||
description = "每次点击/导航后自动截图,用于视觉验证"
|
||||
|
||||
[i18n.zh.settings.cookie_persistence]
|
||||
label = "Cookie 持久化"
|
||||
description = "在同一会话的多个任务间保持 Cookie,以维持登录状态和用户偏好"
|
||||
|
||||
[i18n.zh.settings.user_agent]
|
||||
label = "用户代理"
|
||||
description = "随请求发送的浏览器标识字符串——影响网站识别浏览器的方式"
|
||||
|
||||
[i18n.zh.settings.viewport_size]
|
||||
label = "视口大小"
|
||||
description = "浏览器窗口尺寸——影响响应式布局和网站呈现的版本"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "ブラウザ Hand"
|
||||
description = "自律型ウェブブラウザ——サイトのナビゲーション、フォーム入力、ボタンクリック、ユーザー承認付きの複数ステップWebタスクの実行"
|
||||
category = "生産性"
|
||||
|
||||
[i18n.ja.settings.headless]
|
||||
label = "ヘッドレスモード"
|
||||
description = "ブラウザウィンドウを表示せずに実行する(サーバー環境に推奨)"
|
||||
|
||||
[i18n.ja.settings.approval_mode]
|
||||
label = "購入承認"
|
||||
description = "購入や支払いを完了する前にユーザーの明示的な確認を求める"
|
||||
|
||||
[i18n.ja.settings.max_pages_per_task]
|
||||
label = "タスクあたりの最大ページ数"
|
||||
description = "暴走的なブラウジングを防ぐため、タスクごとに許可されるページ遷移の最大数"
|
||||
|
||||
[i18n.ja.settings.default_wait]
|
||||
label = "操作後のデフォルト待機時間"
|
||||
description = "クリックやナビゲーション後、ページが安定するまでの待機時間"
|
||||
|
||||
[i18n.ja.settings.screenshot_on_action]
|
||||
label = "操作後のスクリーンショット"
|
||||
description = "クリック/ナビゲーションのたびに自動的にスクリーンショットを撮影し、視覚的に確認する"
|
||||
|
||||
[i18n.ja.settings.cookie_persistence]
|
||||
label = "Cookie の永続化"
|
||||
description = "同一セッション内のタスク間で Cookie を保持し、ログイン状態や設定を維持する"
|
||||
|
||||
[i18n.ja.settings.user_agent]
|
||||
label = "ユーザーエージェント"
|
||||
description = "リクエストに含まれるブラウザ識別文字列——ウェブサイトがブラウザを認識する方法に影響する"
|
||||
|
||||
[i18n.ja.settings.viewport_size]
|
||||
label = "ビューポートサイズ"
|
||||
description = "ブラウザウィンドウの寸法——レスポンシブレイアウトや表示されるサイトのバージョンに影響する"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Navegador"
|
||||
description = "Navegador web autónomo — navega sitios, completa formularios, hace clic en botones y realiza tareas web de múltiples pasos con aprobación del usuario para compras"
|
||||
category = "Productividad"
|
||||
|
||||
[i18n.es.settings.headless]
|
||||
label = "Modo sin interfaz"
|
||||
description = "Ejecutar el navegador sin ventana visible (recomendado para servidores)"
|
||||
|
||||
[i18n.es.settings.approval_mode]
|
||||
label = "Aprobación de compras"
|
||||
description = "Requerir confirmación explícita del usuario antes de completar cualquier compra o pago"
|
||||
|
||||
[i18n.es.settings.max_pages_per_task]
|
||||
label = "Máximo de páginas por tarea"
|
||||
description = "Número máximo de navegaciones de página permitidas por tarea para evitar navegación descontrolada"
|
||||
|
||||
[i18n.es.settings.default_wait]
|
||||
label = "Espera predeterminada tras acción"
|
||||
description = "Cuánto tiempo esperar después de hacer clic o navegar para que la página se estabilice"
|
||||
|
||||
[i18n.es.settings.screenshot_on_action]
|
||||
label = "Captura de pantalla tras acciones"
|
||||
description = "Tomar automáticamente una captura de pantalla después de cada clic/navegación para verificación visual"
|
||||
|
||||
[i18n.es.settings.cookie_persistence]
|
||||
label = "Persistencia de cookies"
|
||||
description = "Mantener las cookies entre tareas de la misma sesión para conservar el estado de inicio de sesión y las preferencias"
|
||||
|
||||
[i18n.es.settings.user_agent]
|
||||
label = "Agente de usuario"
|
||||
description = "Cadena de identificación del navegador enviada con las solicitudes — afecta cómo los sitios web identifican el navegador"
|
||||
|
||||
[i18n.es.settings.viewport_size]
|
||||
label = "Tamaño de la ventana"
|
||||
description = "Dimensiones de la ventana del navegador — afecta el diseño responsivo y la versión del sitio que se muestra"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand Navigateur"
|
||||
description = "Navigateur web autonome — navigue sur les sites, remplit les formulaires, clique sur les boutons et exécute des tâches web multi-étapes avec approbation utilisateur pour les achats"
|
||||
category = "Productivité"
|
||||
|
||||
[i18n.fr.settings.headless]
|
||||
label = "Mode sans interface"
|
||||
description = "Exécuter le navigateur sans fenêtre visible (recommandé pour les serveurs)"
|
||||
|
||||
[i18n.fr.settings.approval_mode]
|
||||
label = "Approbation des achats"
|
||||
description = "Exiger la confirmation explicite de l'utilisateur avant de finaliser tout achat ou paiement"
|
||||
|
||||
[i18n.fr.settings.max_pages_per_task]
|
||||
label = "Pages maximum par tâche"
|
||||
description = "Nombre maximum de navigations de page autorisées par tâche pour éviter une navigation incontrôlée"
|
||||
|
||||
[i18n.fr.settings.default_wait]
|
||||
label = "Attente par défaut après action"
|
||||
description = "Durée d'attente après un clic ou une navigation pour que la page se stabilise"
|
||||
|
||||
[i18n.fr.settings.screenshot_on_action]
|
||||
label = "Capture d'écran après action"
|
||||
description = "Prendre automatiquement une capture d'écran après chaque clic/navigation pour vérification visuelle"
|
||||
|
||||
[i18n.fr.settings.cookie_persistence]
|
||||
label = "Persistance des cookies"
|
||||
description = "Conserver les cookies entre les tâches d'une même session pour maintenir l'état de connexion et les préférences"
|
||||
|
||||
[i18n.fr.settings.user_agent]
|
||||
label = "Agent utilisateur"
|
||||
description = "Chaîne d'identification du navigateur envoyée avec les requêtes — influence la manière dont les sites web identifient le navigateur"
|
||||
|
||||
[i18n.fr.settings.viewport_size]
|
||||
label = "Taille de la fenêtre"
|
||||
description = "Dimensions de la fenêtre du navigateur — influence la mise en page responsive et la version du site affichée"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Browser-Hand"
|
||||
description = "Autonomer Webbrowser — navigiert Websites, füllt Formulare aus, klickt Schaltflächen und führt mehrstufige Webaufgaben mit Benutzerfreigabe für Käufe aus"
|
||||
category = "Produktivität"
|
||||
|
||||
[i18n.de.settings.headless]
|
||||
label = "Headless-Modus"
|
||||
description = "Browser ohne sichtbares Fenster ausführen (empfohlen für Server)"
|
||||
|
||||
[i18n.de.settings.approval_mode]
|
||||
label = "Kaufgenehmigung"
|
||||
description = "Ausdrückliche Benutzerbestätigung vor dem Abschluss eines Kaufs oder einer Zahlung erforderlich"
|
||||
|
||||
[i18n.de.settings.max_pages_per_task]
|
||||
label = "Maximale Seiten pro Aufgabe"
|
||||
description = "Maximale Anzahl erlaubter Seitennavigationen pro Aufgabe, um unkontrolliertes Surfen zu verhindern"
|
||||
|
||||
[i18n.de.settings.default_wait]
|
||||
label = "Standard-Wartezeit nach Aktion"
|
||||
description = "Wartezeit nach einem Klick oder einer Navigation, bis sich die Seite stabilisiert hat"
|
||||
|
||||
[i18n.de.settings.screenshot_on_action]
|
||||
label = "Screenshot nach Aktion"
|
||||
description = "Nach jedem Klick/jeder Navigation automatisch einen Screenshot für visuelle Überprüfung erstellen"
|
||||
|
||||
[i18n.de.settings.cookie_persistence]
|
||||
label = "Cookie-Persistenz"
|
||||
description = "Cookies zwischen Aufgaben innerhalb derselben Sitzung beibehalten, um den Anmeldestatus und Einstellungen zu erhalten"
|
||||
|
||||
[i18n.de.settings.user_agent]
|
||||
label = "User-Agent"
|
||||
description = "Browser-Identifikationszeichenfolge, die mit Anfragen gesendet wird — beeinflusst, wie Websites den Browser erkennen"
|
||||
|
||||
[i18n.de.settings.viewport_size]
|
||||
label = "Fenstergröße"
|
||||
description = "Abmessungen des Browserfensters — beeinflusst das responsive Layout und welche Version einer Website angezeigt wird"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "브라우저 Hand"
|
||||
description = "자율 웹 브라우저 — 사이트 탐색, 양식 작성, 버튼 클릭, 구매 시 사용자 승인을 받아 다단계 웹 작업 수행"
|
||||
category = "생산성"
|
||||
|
||||
[i18n.ko.settings.headless]
|
||||
label = "헤드리스 모드"
|
||||
description = "브라우저 창을 표시하지 않고 실행 (서버 환경에 권장)"
|
||||
|
||||
[i18n.ko.settings.approval_mode]
|
||||
label = "구매 승인"
|
||||
description = "구매 또는 결제 완료 전 사용자의 명시적 확인 필요"
|
||||
|
||||
[i18n.ko.settings.max_pages_per_task]
|
||||
label = "작업당 최대 페이지 수"
|
||||
description = "작업당 허용되는 최대 페이지 탐색 횟수 (무한 브라우징 방지)"
|
||||
|
||||
[i18n.ko.settings.default_wait]
|
||||
label = "동작 후 기본 대기"
|
||||
description = "클릭 또는 탐색 후 페이지가 안정될 때까지 대기하는 시간"
|
||||
|
||||
[i18n.ko.settings.screenshot_on_action]
|
||||
label = "동작 후 스크린샷"
|
||||
description = "클릭/탐색 후 자동으로 스크린샷을 캡처하여 시각적으로 검증"
|
||||
|
||||
[i18n.ko.settings.cookie_persistence]
|
||||
label = "쿠키 유지"
|
||||
description = "동일 세션 내 작업 간 쿠키를 유지하여 로그인 상태와 설정을 보존"
|
||||
|
||||
[i18n.ko.settings.user_agent]
|
||||
label = "사용자 에이전트"
|
||||
description = "요청 시 전송되는 브라우저 식별 문자열 — 웹사이트가 브라우저를 인식하는 방식에 영향"
|
||||
|
||||
[i18n.ko.settings.viewport_size]
|
||||
label = "뷰포트 크기"
|
||||
description = "브라우저 창 크기 — 반응형 레이아웃과 표시되는 사이트 버전에 영향"
|
||||
+267
-148
@@ -81,8 +81,140 @@ runtime: prompt_only
|
||||
|
||||
---
|
||||
|
||||
## Generic Selector Strategies (Priority Order)
|
||||
|
||||
Use selectors that are resilient to UI redesigns. Prefer semantic and accessibility-based selectors over class names.
|
||||
|
||||
### Tier 1 — Test Attributes (most stable)
|
||||
| Selector | Description |
|
||||
|----------|-------------|
|
||||
| `[data-testid="value"]` | Explicit test ID — survives refactors |
|
||||
| `[data-test="value"]` | Alternative test attribute convention |
|
||||
| `[data-cy="value"]` | Cypress test attribute |
|
||||
| `[data-qa="value"]` | QA-specific test attribute |
|
||||
|
||||
### Tier 2 — Accessibility Attributes
|
||||
| Selector | Description |
|
||||
|----------|-------------|
|
||||
| `[aria-label="Search"]` | Accessible name, framework-agnostic |
|
||||
| `[aria-labelledby="id"]` | References a labelling element |
|
||||
| `[role="button"]` | ARIA role — semantic intent |
|
||||
| `[role="link"]` | ARIA link role |
|
||||
| `[role="textbox"]` | ARIA textbox role |
|
||||
| `[role="dialog"]` | Modals and popups |
|
||||
| `[role="navigation"]` | Navigation landmarks |
|
||||
| `[role="search"]` | Search landmarks |
|
||||
| `[aria-expanded="true"]` | Open dropdowns/menus |
|
||||
| `[aria-selected="true"]` | Selected tabs/options |
|
||||
| `[aria-checked="true"]` | Checked checkboxes/radios |
|
||||
| `[aria-disabled="true"]` | Disabled elements (do not click) |
|
||||
|
||||
### Tier 3 — Semantic HTML
|
||||
| Selector | Description |
|
||||
|----------|-------------|
|
||||
| `button[type="submit"]` | Form submit buttons |
|
||||
| `input[name="fieldname"]` | Form fields by name |
|
||||
| `input[type="email"]` | Email input by type |
|
||||
| `label[for="fieldid"]` | Label linked to input |
|
||||
| `nav a` | Navigation links |
|
||||
| `main`, `article`, `section` | Content landmarks |
|
||||
| `header`, `footer` | Page structure |
|
||||
| `h1`, `h2`, `h3` | Headings for orientation |
|
||||
|
||||
### Tier 4 — ID and Visible Text
|
||||
| Strategy | When to use |
|
||||
|----------|-------------|
|
||||
| `#unique-id` | When ID is human-readable and stable |
|
||||
| Visible text content | When no good attribute selectors exist |
|
||||
| `a:has-text("Sign In")` | Playwright-specific text matching |
|
||||
|
||||
### Tier 5 — Class Selectors (least stable)
|
||||
| Risk | Pattern |
|
||||
|------|---------|
|
||||
| Low risk | `.btn-primary`, `.nav-link` (design-system classes) |
|
||||
| Medium risk | `.header-search-input` (component-specific) |
|
||||
| High risk | `.css-1a2b3c`, `.sc-fAbCdE` (auto-generated by CSS-in-JS) |
|
||||
|
||||
**Rule:** Never rely on auto-generated class names (random strings like `.css-xyz123`). These change on every build.
|
||||
|
||||
## Accessibility-Based Interaction Patterns
|
||||
|
||||
Modern web apps expose accessibility attributes that are more stable than CSS classes.
|
||||
|
||||
### Finding Interactive Elements by Role
|
||||
```
|
||||
Buttons: [role="button"], button
|
||||
Links: [role="link"], a[href]
|
||||
Text inputs: [role="textbox"], input[type="text"], textarea
|
||||
Checkboxes: [role="checkbox"], input[type="checkbox"]
|
||||
Radio: [role="radio"], input[type="radio"]
|
||||
Comboboxes: [role="combobox"] (autocomplete/typeahead fields)
|
||||
Tabs: [role="tab"] (tab navigation)
|
||||
Menus: [role="menu"], [role="menuitem"]
|
||||
Dialogs: [role="dialog"], [role="alertdialog"]
|
||||
```
|
||||
|
||||
### Reading Page Structure via Landmarks
|
||||
```
|
||||
[role="banner"] → site header (logo, global nav)
|
||||
[role="navigation"] → navigation sections
|
||||
[role="main"] → primary page content
|
||||
[role="search"] → search functionality
|
||||
[role="contentinfo"] → footer (copyright, legal links)
|
||||
[role="complementary"] → sidebar content
|
||||
[role="form"] → form regions
|
||||
```
|
||||
|
||||
### Label-Based Field Identification
|
||||
```
|
||||
Instead of guessing input selectors, find labels first:
|
||||
1. browser_read_page → look for label text (e.g., "Email Address")
|
||||
2. Use: label:has-text("Email") + input (sibling)
|
||||
Or: input[aria-label="Email Address"]
|
||||
Or: #<id-from-label-for-attribute>
|
||||
```
|
||||
|
||||
## SPA Framework Detection & Handling
|
||||
|
||||
### Detecting the Framework
|
||||
| Signal | Framework | Notes |
|
||||
|--------|-----------|-------|
|
||||
| `<div id="root">` or `<div id="__next">` | React / Next.js | Content rendered client-side |
|
||||
| `<div id="app">` with `data-v-` attributes | Vue.js / Nuxt | `data-v-xxxxx` are scoped style markers |
|
||||
| `<app-root>` or custom element tags | Angular | Uses web component-like tags |
|
||||
| `<div id="svelte">` or compiled class names | Svelte / SvelteKit | Minimal runtime footprint |
|
||||
| URL contains `#/` hash routing | Any SPA | Client-side routing via hash |
|
||||
| `__NEXT_DATA__` script tag | Next.js | Server-side rendering with hydration |
|
||||
| `__NUXT__` or `__NUXT_DATA__` in page | Nuxt.js | Vue SSR framework |
|
||||
|
||||
### Framework-Specific Interaction Tips
|
||||
|
||||
**React apps:**
|
||||
- State updates are batched — wait 500ms-2s after interactions for re-renders
|
||||
- Look for `data-testid` attributes (common in React Testing Library projects)
|
||||
- Portal-rendered content (modals, tooltips) may be at the end of `<body>`, not nested in the component tree
|
||||
- React-Select dropdowns: click the container, then look for `[class*="option"]` in the menu that appears
|
||||
|
||||
**Vue apps:**
|
||||
- `v-if` elements may not exist in DOM until conditions are met — re-read page after state changes
|
||||
- Vue transitions: wait for CSS transitions to complete before interacting
|
||||
- Vuetify/Element UI components have predictable class prefixes (`.v-btn`, `.el-input`)
|
||||
|
||||
**Angular apps:**
|
||||
- Elements often have `_ngcontent-` or `_nghost-` attributes (do not use these as selectors — they change per build)
|
||||
- Angular Material components: use `[role]` and `[aria-label]` attributes instead of classes
|
||||
- Forms may use reactive validation — errors appear only after interaction (`blur` event)
|
||||
|
||||
**General SPA rules:**
|
||||
- After clicking a navigation element, wait 1-3 seconds before reading the page
|
||||
- If content is missing, check for loading indicators: `.loading`, `.spinner`, `[aria-busy="true"]`, `.skeleton`
|
||||
- Retry `browser_read_page` up to 3 times with 2-second intervals before giving up
|
||||
- URL changes without full page reload confirm SPA routing — do not expect `browser_navigate` events
|
||||
|
||||
## Site-Specific Selector Patterns
|
||||
|
||||
These are reference selectors for common sites. They change frequently — always verify with `browser_read_page` if a selector fails, then construct a fresh selector from the live DOM.
|
||||
|
||||
### Google Search
|
||||
| Element | Selector |
|
||||
|---------|----------|
|
||||
@@ -90,45 +222,26 @@ runtime: prompt_only
|
||||
| Search button | `input[name="btnK"]`, `button[type="submit"]` |
|
||||
| Result titles | `h3` (within `#search`) |
|
||||
| Result links | `#search a[href^="http"]` |
|
||||
| Result snippets | `.VwiC3b`, `div[data-sncf]` |
|
||||
| "Next" pagination | `a#pnnext` |
|
||||
| "People also ask" | `.related-question-pair` |
|
||||
|
||||
### Amazon
|
||||
| Element | Selector |
|
||||
|---------|----------|
|
||||
| Search input | `#twotabsearchtextbox` |
|
||||
| Search button | `#nav-search-submit-button` |
|
||||
| Product titles | `h2 a.a-link-normal span` |
|
||||
| Prices | `.a-price .a-offscreen`, `.a-price-whole` |
|
||||
| Add to cart | `#add-to-cart-button` |
|
||||
| Buy now | `#buy-now-button` |
|
||||
| Quantity dropdown | `#quantity` |
|
||||
| Star rating | `i.a-icon-star span` |
|
||||
| Cart count | `#nav-cart-count` |
|
||||
|
||||
### LinkedIn
|
||||
| Element | Selector |
|
||||
|---------|----------|
|
||||
| Username | `#username` |
|
||||
| Password | `#password` |
|
||||
| Sign in | `button[type="submit"]` |
|
||||
| Search | `input[role="combobox"]` |
|
||||
| Profile name | `.text-heading-xlarge` |
|
||||
| Connection button | `button[aria-label*="Connect"]` |
|
||||
| Message button | `button[aria-label*="Message"]` |
|
||||
|
||||
### GitHub
|
||||
| Element | Selector |
|
||||
|---------|----------|
|
||||
| Search | `input[name="q"]` |
|
||||
| Repository name | `[itemprop="name"] a` |
|
||||
| Star button | `button[aria-label*="Star"]` |
|
||||
| File contents | `.blob-code-inner` |
|
||||
| Issue title | `#issue_title`, `.js-issue-title` |
|
||||
| Submit button | `button[type="submit"]` |
|
||||
|
||||
Note: Site selectors change frequently. When a saved selector fails, fall back to `browser_read_page` to discover the current DOM structure, then construct a new selector from the live page.
|
||||
Note: When a saved selector fails, use `browser_read_page` to discover the current DOM, then build a new selector from live content. Prefer `[data-testid]`, `[aria-label]`, or visible text over fragile class-based selectors.
|
||||
|
||||
---
|
||||
|
||||
@@ -246,49 +359,118 @@ After browser_navigate or browser_click that triggers navigation:
|
||||
```
|
||||
|
||||
### SPA (Single Page Application) Handling
|
||||
SPAs like React, Angular, and Vue do not trigger traditional page loads:
|
||||
SPAs (React, Angular, Vue, Svelte) do not trigger traditional page loads. Client-side routing means the browser URL changes but no network navigation occurs.
|
||||
|
||||
```
|
||||
1. browser_click → triggers route change
|
||||
1. browser_click → triggers route change (URL updates but no page reload)
|
||||
2. browser_read_page → may return stale content from previous view
|
||||
3. Wait 1-2 seconds for client-side rendering
|
||||
4. browser_read_page → should now show updated content
|
||||
5. If content still stale → look for loading spinners:
|
||||
- `.loading`, `.spinner`, `[aria-busy="true"]`
|
||||
- Wait until these elements disappear
|
||||
6. browser_read_page → final attempt
|
||||
3. Check for loading indicators in the output:
|
||||
- Text: "Loading...", "Please wait", skeleton placeholders
|
||||
- Attributes: [aria-busy="true"]
|
||||
- Classes: .loading, .spinner, .skeleton, .placeholder
|
||||
4. If loading detected OR content stale → wait 2 seconds
|
||||
5. browser_read_page → retry (attempt 2 of 3)
|
||||
6. If still stale → wait 3 seconds → browser_read_page (attempt 3 of 3)
|
||||
7. If content never updates:
|
||||
a. browser_screenshot → check if content is visually present but not captured as text
|
||||
b. The content may be inside an iframe or shadow DOM — try alternative access
|
||||
c. Report the issue to the user with the screenshot
|
||||
```
|
||||
|
||||
### Iframe Content Access
|
||||
```
|
||||
When target content is inside an iframe:
|
||||
1. browser_read_page → look for <iframe> elements and their src attributes
|
||||
2. browser_navigate → directly to the iframe src URL (if same-origin)
|
||||
3. Interact with the content normally
|
||||
4. browser_navigate → back to the parent page when done
|
||||
Note: Cross-origin iframes may block direct access. Inform the user if this occurs.
|
||||
```
|
||||
|
||||
### Shadow DOM Awareness
|
||||
```
|
||||
Web components using shadow DOM hide their internals from normal CSS selectors:
|
||||
1. If a known element is not found by any selector, suspect shadow DOM
|
||||
2. browser_screenshot → visually confirm the element exists on the page
|
||||
3. Try interacting via visible text content (may pierce shadow boundaries)
|
||||
4. If interaction fails, inform the user that the element is inside a shadow root
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Recovery Strategies
|
||||
|
||||
### Error Recovery Decision Tree
|
||||
When any interaction fails, walk through this decision tree top-to-bottom:
|
||||
|
||||
```
|
||||
INTERACTION FAILED
|
||||
│
|
||||
├─ Is this the correct page?
|
||||
│ ├─ NO → browser_read_page to check URL
|
||||
│ │ ├─ Redirected to login? → re-authenticate, then retry
|
||||
│ │ ├─ Redirected to error page? → handle HTTP error (see below)
|
||||
│ │ └─ Wrong page entirely? → browser_navigate to correct URL
|
||||
│ └─ YES ↓
|
||||
│
|
||||
├─ Is an overlay blocking the element?
|
||||
│ ├─ YES → dismiss overlay (cookie banner, modal, chat widget)
|
||||
│ │ then retry the original interaction
|
||||
│ └─ NO ↓
|
||||
│
|
||||
├─ Does the element exist in the DOM?
|
||||
│ ├─ NO → page may not have finished rendering
|
||||
│ │ ├─ Wait 2 seconds → browser_read_page → retry (up to 3 times)
|
||||
│ │ ├─ Scroll the page to trigger lazy loading → retry
|
||||
│ │ ├─ Try alternative selectors (see priority order below)
|
||||
│ │ └─ Still not found? → browser_screenshot → report to user
|
||||
│ └─ YES ↓
|
||||
│
|
||||
├─ Is the element visible and interactive?
|
||||
│ ├─ Disabled ([disabled], [aria-disabled="true"]) → inform user, cannot interact
|
||||
│ ├─ Hidden (display:none, off-screen) → may be inside collapsed section, try expanding
|
||||
│ ├─ Covered by another element → identify and dismiss the covering element
|
||||
│ └─ YES ↓
|
||||
│
|
||||
├─ Did the click/type register?
|
||||
│ ├─ NO → JavaScript may not have attached handlers yet
|
||||
│ │ ├─ Wait 2 seconds → retry
|
||||
│ │ ├─ Try clicking a more specific child element
|
||||
│ │ └─ Try clicking by visible text instead of CSS selector
|
||||
│ └─ YES ↓
|
||||
│
|
||||
└─ Did the expected state change occur?
|
||||
├─ NO → SPA may need time to re-render
|
||||
│ ├─ Wait 2-3 seconds → browser_read_page to verify
|
||||
│ ├─ Check for loading indicators ([aria-busy], .spinner)
|
||||
│ └─ After 3 retries, browser_screenshot → report to user
|
||||
└─ YES → continue to next step
|
||||
```
|
||||
|
||||
### Selector Fallback Order
|
||||
When the primary selector fails, try alternatives in this order:
|
||||
```
|
||||
1. [data-testid="..."], [data-test="..."], [data-cy="..."] — test attributes
|
||||
2. [aria-label="..."], [role="button"] — accessibility
|
||||
3. Visible text content: a:has-text("Sign In") — human-readable
|
||||
4. input[name="..."], input[type="..."] — form semantics
|
||||
5. #id — unique ID
|
||||
6. [class*="keyword"] — partial class match (last resort)
|
||||
```
|
||||
|
||||
### Quick Reference
|
||||
| Error | Recovery |
|
||||
|-------|----------|
|
||||
| Element not found | Try alternative selector, use visible text, scroll page |
|
||||
| Page timeout | Retry navigation, check URL |
|
||||
| Element not found | Walk selector fallback order, scroll page, screenshot |
|
||||
| Page timeout | Retry URL once, try base domain, report to user |
|
||||
| Login required | Inform user, ask for credentials |
|
||||
| CAPTCHA | Cannot solve — inform user |
|
||||
| Pop-up/modal | Click dismiss/close button first |
|
||||
| Cookie consent | Click "Accept" or dismiss banner |
|
||||
| Rate limited | Wait 30s, retry |
|
||||
| Wrong page | Use browser_read_page to verify, navigate back |
|
||||
|
||||
### Element Not Found Recovery
|
||||
When a selector fails, follow this escalation path:
|
||||
```
|
||||
1. RETRY: Try the same selector once more (transient timing issue)
|
||||
2. SCROLL: Scroll the page to trigger lazy loading, then retry
|
||||
3. ALTERNATIVE SELECTOR: Try these fallback patterns in order:
|
||||
a. By visible text content (button text, link text)
|
||||
b. By ARIA role: [role="button"], [role="link"]
|
||||
c. By data-testid: [data-testid="..."] (if site uses them)
|
||||
d. By partial attribute match: [class*="submit"], [id*="login"]
|
||||
e. By structural position: form button:last-child
|
||||
4. READ PAGE: Use browser_read_page to see current DOM structure
|
||||
5. SCREENSHOT: Use browser_screenshot to visually identify the element
|
||||
6. REPORT: If all fail, inform user with what was tried and the current page state
|
||||
```
|
||||
| CAPTCHA | Screenshot and inform user — cannot solve |
|
||||
| Pop-up/modal | Dismiss first, then retry original action |
|
||||
| Cookie consent | Click "Accept All" or dismiss banner |
|
||||
| Rate limited (429) | Wait 30s, retry; after 3 failures, stop and report |
|
||||
| Session expired | Detect login redirect, re-authenticate, resume |
|
||||
| Wrong page | Verify URL, navigate back or to correct page |
|
||||
| Empty SPA content | Wait 3-5s for render, retry read up to 3 times |
|
||||
|
||||
### Navigation Failure Recovery
|
||||
```
|
||||
@@ -306,116 +488,79 @@ When a selector fails, follow this escalation path:
|
||||
|
||||
3. HTTP errors observed in page content:
|
||||
- 403 Forbidden → site may be blocking automation, inform user
|
||||
- 404 Not Found → URL is stale or incorrect, search for correct URL
|
||||
- 404 Not Found → URL is stale or incorrect, try searching for the correct page
|
||||
- 429 Too Many Requests → wait 60 seconds, retry with longer intervals
|
||||
- 500/502/503 → server issue, retry after 30 seconds (max 3 retries)
|
||||
```
|
||||
|
||||
### Stale Element Recovery
|
||||
Elements can become stale when the page re-renders (common in SPAs):
|
||||
### Stale Element Recovery (SPA-Specific)
|
||||
Elements become stale when the page re-renders — common in React, Vue, and Angular:
|
||||
```
|
||||
1. Identify the stale interaction (click that failed after page update)
|
||||
1. Identify the stale interaction (click that produced no result or error)
|
||||
2. browser_read_page → get fresh DOM snapshot
|
||||
3. Re-locate the element using the same or updated selector
|
||||
4. Retry the interaction on the fresh element
|
||||
5. If element has moved or changed structure, use browser_screenshot
|
||||
to visually identify its new position
|
||||
3. Check if the element's selector still matches in the new DOM
|
||||
4. If not, construct a new selector from the fresh page content
|
||||
5. Retry the interaction with the updated selector
|
||||
6. If element has moved, use browser_screenshot to find its new location
|
||||
```
|
||||
|
||||
### Pop-up and Overlay Dismissal
|
||||
```
|
||||
Order of priority when dealing with overlays blocking interaction:
|
||||
Order of priority when overlays block interaction:
|
||||
1. Cookie consent banners:
|
||||
- Click: button containing "Accept", "Agree", "OK", "Got it"
|
||||
- Selectors: #cookie-accept, .cookie-consent button, [data-action="accept"]
|
||||
- Fallback: .cookie-banner .close, #cookie-close
|
||||
- Selectors: [aria-label*="cookie" i] button, #onetrust-accept-btn-handler
|
||||
- Text: "Accept All", "Accept Cookies", "Agree", "OK", "Got it"
|
||||
- Fallback: .cookie-banner .close, #cookie-close, [aria-label="Close"]
|
||||
|
||||
2. Newsletter/subscription modals:
|
||||
- Click: close/dismiss button
|
||||
- Selectors: .modal .close, [aria-label="Close"], button.dismiss
|
||||
- Fallback: press Escape key (if supported)
|
||||
- Selectors: [role="dialog"] [aria-label="Close"], .modal .close, button.dismiss
|
||||
- Fallback: press Escape key (via browser_type on body element)
|
||||
|
||||
3. Chat widgets:
|
||||
- Usually do not block interaction (z-index overlay)
|
||||
- If blocking, click minimize/close on the widget
|
||||
- Usually do not block (z-index layer); if blocking, click minimize/close
|
||||
|
||||
4. Age verification gates:
|
||||
- Click "Yes" / "I am over 18" / "Enter"
|
||||
- May need to select a birth date from dropdowns
|
||||
|
||||
5. Location/notification permission prompts:
|
||||
- These are browser-level, not DOM elements
|
||||
- Usually auto-dismissed by Playwright's browser context settings
|
||||
5. App install banners:
|
||||
- Look for "Continue in browser", "Not now", or close/dismiss buttons
|
||||
|
||||
6. Browser-level permission prompts:
|
||||
- Auto-dismissed by Playwright context settings
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Anti-Detection Techniques
|
||||
|
||||
### User Agent Strategy
|
||||
Rotate user agents to appear as a normal browser. Common realistic user agents:
|
||||
```
|
||||
Desktop Chrome (Windows):
|
||||
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
|
||||
|
||||
Desktop Chrome (macOS):
|
||||
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
|
||||
|
||||
Desktop Firefox (Windows):
|
||||
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0
|
||||
|
||||
Mobile Chrome (Android):
|
||||
Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36
|
||||
|
||||
Mobile Safari (iOS):
|
||||
Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1
|
||||
```
|
||||
|
||||
### Viewport Randomization
|
||||
Use realistic viewport sizes with slight variation to avoid fingerprinting:
|
||||
```
|
||||
Common realistic viewports:
|
||||
Desktop: 1920x1080, 1366x768, 1536x864, 1440x900, 1280x720
|
||||
Tablet: 1024x768, 768x1024 (portrait), 1280x800
|
||||
Mobile: 375x812, 390x844, 360x780, 414x896
|
||||
|
||||
Add random offsets (1-20px) to avoid exact-match detection:
|
||||
1920x1080 → 1923x1077 (slightly varied)
|
||||
```
|
||||
|
||||
### Behavioral Patterns
|
||||
Automation detection looks for non-human interaction patterns. Mitigate by:
|
||||
```
|
||||
1. TIMING: Do not click or type instantly after page load
|
||||
1. TIMING: Do not interact instantly after page load
|
||||
- Wait 1-3 seconds before first interaction
|
||||
- Insert 0.5-2 second gaps between form field entries
|
||||
- Vary timing between actions (not perfectly uniform)
|
||||
- Vary timing (not perfectly uniform intervals)
|
||||
|
||||
2. NAVIGATION: Follow natural browsing patterns
|
||||
- Visit homepage before going directly to deep URLs
|
||||
- Click through navigation menus instead of using direct URLs when possible
|
||||
- Scroll the page before interacting with below-the-fold content
|
||||
- Visit homepage before deep URLs when possible
|
||||
- Click through navigation instead of using direct URLs
|
||||
- Scroll before interacting with below-the-fold content
|
||||
|
||||
3. MOUSE/KEYBOARD: Simulate realistic input
|
||||
- Type into fields character by character (browser_type handles this)
|
||||
3. INPUT: Simulate realistic behavior
|
||||
- Type character by character (browser_type handles this)
|
||||
- Click buttons rather than submitting forms programmatically
|
||||
- Do not fill hidden honeypot fields (fields with display:none or visibility:hidden)
|
||||
|
||||
4. AVOID DETECTABLE PATTERNS:
|
||||
- Do not fill hidden honeypot fields (see below)
|
||||
- Do not request pages faster than 1 per 3 seconds on the same domain
|
||||
- Do not access robots.txt-blocked paths
|
||||
- Do not make requests in perfectly uniform intervals
|
||||
```
|
||||
|
||||
### Honeypot Field Detection
|
||||
Some forms include invisible fields designed to catch bots:
|
||||
```
|
||||
Do NOT fill fields that have:
|
||||
- style="display: none"
|
||||
- style="visibility: hidden"
|
||||
- style="display: none" or style="visibility: hidden"
|
||||
- class="hidden", class="d-none", class="sr-only"
|
||||
- type="hidden" (unless it is a legitimate CSRF token or form ID)
|
||||
- Position: absolute with left: -9999px or similar off-screen placement
|
||||
- Position: absolute with left: -9999px (off-screen placement)
|
||||
|
||||
Use browser_read_page to inspect field visibility before filling.
|
||||
```
|
||||
@@ -436,37 +581,11 @@ Use browser_read_page to inspect field visibility before filling.
|
||||
| Unexpected page state | Diagnose navigation or rendering issues |
|
||||
|
||||
### Content Extraction Patterns
|
||||
|
||||
**Extracting structured data from tables:**
|
||||
```
|
||||
1. browser_read_page → get full page text
|
||||
2. Identify table boundaries in the text output
|
||||
3. Parse rows and columns from the structured text
|
||||
4. memory_store → save as structured data for comparison
|
||||
```
|
||||
|
||||
**Extracting specific data points:**
|
||||
```
|
||||
1. browser_read_page → get page content
|
||||
2. Search output for relevant labels/headings:
|
||||
- "Price:", "Total:", "Subtotal:" → monetary values
|
||||
- "In Stock", "Available", "Sold Out" → availability
|
||||
- "Rating:", stars → review scores
|
||||
- "SKU:", "Item #:" → product identifiers
|
||||
3. Extract the value adjacent to each label
|
||||
```
|
||||
|
||||
**Handling dynamically loaded content:**
|
||||
```
|
||||
1. browser_read_page → check if content placeholder exists
|
||||
2. If content shows "Loading..." or skeleton elements:
|
||||
a. Wait 2-3 seconds
|
||||
b. browser_read_page → retry
|
||||
3. If content requires scroll-to-load (infinite scroll):
|
||||
a. Extract visible data
|
||||
b. Scroll down (click a lower element or use page navigation)
|
||||
c. browser_read_page → extract newly loaded data
|
||||
d. Repeat until desired amount collected or no new content appears
|
||||
Tables: browser_read_page → identify table boundaries → parse rows/columns → memory_store
|
||||
Data: browser_read_page → search for labels ("Price:", "In Stock", "Rating:") → extract adjacent values
|
||||
Dynamic: browser_read_page → if "Loading..." or skeleton → wait 2-3s → retry
|
||||
Scroll: extract visible data → scroll down → browser_read_page → repeat until complete (max 10 cycles)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -645,6 +645,289 @@ frequency = "on-demand"
|
||||
token_consumption = "medium"
|
||||
default_active = false
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "视频剪辑 Hand"
|
||||
description = "将长视频自动剪辑为病毒式短视频,配有字幕和缩略图"
|
||||
category = "内容"
|
||||
|
||||
[i18n.zh.settings.stt_provider]
|
||||
label = "语音转文字服务"
|
||||
description = "用于生成字幕和片段选择的音频转录方式"
|
||||
|
||||
[i18n.zh.settings.tts_provider]
|
||||
label = "文字转语音服务"
|
||||
description = "可选的配音或旁白生成服务"
|
||||
|
||||
[i18n.zh.settings.elevenlabs_api_key]
|
||||
label = "ElevenLabs API 密钥"
|
||||
description = "来自 elevenlabs.io 的高质量文字转语音 API 密钥。选择 ElevenLabs TTS 时必填。"
|
||||
|
||||
[i18n.zh.settings.publish_target]
|
||||
label = "发布目标"
|
||||
description = "处理完成后将短视频发送到哪里。选择"仅本地"则跳过发布。"
|
||||
|
||||
[i18n.zh.settings.telegram_bot_token]
|
||||
label = "Telegram 机器人令牌"
|
||||
description = "从 Telegram 的 @BotFather 获取(例如 123456:ABC-DEF...)。机器人需为目标频道管理员。"
|
||||
|
||||
[i18n.zh.settings.telegram_chat_id]
|
||||
label = "Telegram 聊天 ID"
|
||||
description = "频道:-100XXXXXXXXXX 或 @频道名。群组:数字 ID。可通过 @userinfobot 获取。"
|
||||
|
||||
[i18n.zh.settings.whatsapp_token]
|
||||
label = "WhatsApp 访问令牌"
|
||||
description = "从 Meta 商务管理平台 > 系统用户获取的永久令牌。临时令牌 24 小时后过期。"
|
||||
|
||||
[i18n.zh.settings.whatsapp_phone_id]
|
||||
label = "WhatsApp 电话号码 ID"
|
||||
description = "从 Meta 开发者门户 > WhatsApp > API 设置获取(例如 1234567890)"
|
||||
|
||||
[i18n.zh.settings.whatsapp_recipient]
|
||||
label = "WhatsApp 接收方"
|
||||
description = "国际格式的电话号码,不含 + 号或空格(例如 14155551234)"
|
||||
|
||||
[i18n.zh.settings.approval_mode]
|
||||
label = "审批模式"
|
||||
description = "发布到频道前将短视频加入队列供审核"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "動画クリップ Hand"
|
||||
description = "長尺動画をキャプション付きサムネイル付きのバイラルショートクリップに変換"
|
||||
category = "コンテンツ"
|
||||
|
||||
[i18n.ja.settings.stt_provider]
|
||||
label = "音声テキスト変換プロバイダー"
|
||||
description = "字幕生成とクリップ選択に使用する音声の文字起こし方法"
|
||||
|
||||
[i18n.ja.settings.tts_provider]
|
||||
label = "テキスト音声変換プロバイダー"
|
||||
description = "クリップへのオプションのボイスオーバーまたはナレーション生成"
|
||||
|
||||
[i18n.ja.settings.elevenlabs_api_key]
|
||||
label = "ElevenLabs APIキー"
|
||||
description = "elevenlabs.ioの高品質テキスト音声変換用APIキー。ElevenLabs TTSを選択した場合に必須。"
|
||||
|
||||
[i18n.ja.settings.publish_target]
|
||||
label = "公開先"
|
||||
description = "処理完了後にクリップを送信する先。「ローカルのみ」を選択すると公開をスキップします。"
|
||||
|
||||
[i18n.ja.settings.telegram_bot_token]
|
||||
label = "Telegramボットトークン"
|
||||
description = "Telegramの@BotFatherから取得(例: 123456:ABC-DEF...)。ボットは対象チャンネルの管理者である必要があります。"
|
||||
|
||||
[i18n.ja.settings.telegram_chat_id]
|
||||
label = "TelegramチャットID"
|
||||
description = "チャンネル: -100XXXXXXXXXX または @チャンネル名。グループ: 数値ID。@userinfobot で取得可能。"
|
||||
|
||||
[i18n.ja.settings.whatsapp_token]
|
||||
label = "WhatsAppアクセストークン"
|
||||
description = "Metaビジネス設定 > システムユーザーから取得した永続トークン。一時トークンは24時間で期限切れになります。"
|
||||
|
||||
[i18n.ja.settings.whatsapp_phone_id]
|
||||
label = "WhatsApp電話番号ID"
|
||||
description = "Meta開発者ポータル > WhatsApp > APIセットアップから取得(例: 1234567890)"
|
||||
|
||||
[i18n.ja.settings.whatsapp_recipient]
|
||||
label = "WhatsApp送信先"
|
||||
description = "国際形式の電話番号(+やスペースなし、例: 14155551234)"
|
||||
|
||||
[i18n.ja.settings.approval_mode]
|
||||
label = "承認モード"
|
||||
description = "チャンネルに公開する前にクリップをレビュー用キューに追加する"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Clips de Video"
|
||||
description = "Convierte videos largos en clips cortos virales con subtítulos y miniaturas"
|
||||
category = "Contenido"
|
||||
|
||||
[i18n.es.settings.stt_provider]
|
||||
label = "Proveedor de voz a texto"
|
||||
description = "Cómo se transcribe el audio a texto para subtítulos y selección de clips"
|
||||
|
||||
[i18n.es.settings.tts_provider]
|
||||
label = "Proveedor de texto a voz"
|
||||
description = "Generación opcional de locución o narración para los clips"
|
||||
|
||||
[i18n.es.settings.elevenlabs_api_key]
|
||||
label = "Clave API de ElevenLabs"
|
||||
description = "Clave API de elevenlabs.io para texto a voz de alta calidad. Requerida cuando se selecciona ElevenLabs TTS."
|
||||
|
||||
[i18n.es.settings.publish_target]
|
||||
label = "Destino de publicación"
|
||||
description = "Dónde enviar los clips terminados después del procesamiento. Seleccionar 'Solo local' para omitir la publicación."
|
||||
|
||||
[i18n.es.settings.telegram_bot_token]
|
||||
label = "Token del bot de Telegram"
|
||||
description = "De @BotFather en Telegram (ej. 123456:ABC-DEF...). El bot debe ser administrador del canal de destino."
|
||||
|
||||
[i18n.es.settings.telegram_chat_id]
|
||||
label = "ID de chat de Telegram"
|
||||
description = "Canal: -100XXXXXXXXXX o @nombrechannel. Grupo: ID numérico. Obtener mediante @userinfobot."
|
||||
|
||||
[i18n.es.settings.whatsapp_token]
|
||||
label = "Token de acceso de WhatsApp"
|
||||
description = "Token permanente de Meta Business Settings > Usuarios del sistema. Los tokens temporales expiran en 24h."
|
||||
|
||||
[i18n.es.settings.whatsapp_phone_id]
|
||||
label = "ID de número de teléfono de WhatsApp"
|
||||
description = "Desde el Portal de Desarrolladores de Meta > WhatsApp > Configuración de API (ej. 1234567890)"
|
||||
|
||||
[i18n.es.settings.whatsapp_recipient]
|
||||
label = "Destinatario de WhatsApp"
|
||||
description = "Número de teléfono en formato internacional, sin + ni espacios (ej. 14155551234)"
|
||||
|
||||
[i18n.es.settings.approval_mode]
|
||||
label = "Modo de aprobación"
|
||||
description = "Poner clips en cola para revisión antes de publicarlos en los canales"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand Clips Vidéo"
|
||||
description = "Transforme les longues vidéos en clips courts viraux avec sous-titres et miniatures"
|
||||
category = "Contenu"
|
||||
|
||||
[i18n.fr.settings.stt_provider]
|
||||
label = "Fournisseur de reconnaissance vocale"
|
||||
description = "Méthode de transcription audio pour les sous-titres et la sélection de clips"
|
||||
|
||||
[i18n.fr.settings.tts_provider]
|
||||
label = "Fournisseur de synthèse vocale"
|
||||
description = "Génération optionnelle de voix off ou de narration pour les clips"
|
||||
|
||||
[i18n.fr.settings.elevenlabs_api_key]
|
||||
label = "Clé API ElevenLabs"
|
||||
description = "Clé API de elevenlabs.io pour la synthèse vocale haute qualité. Requise lorsque ElevenLabs TTS est sélectionné."
|
||||
|
||||
[i18n.fr.settings.publish_target]
|
||||
label = "Destination de publication"
|
||||
description = "Où envoyer les clips terminés après traitement. Sélectionner 'Local uniquement' pour ignorer la publication."
|
||||
|
||||
[i18n.fr.settings.telegram_bot_token]
|
||||
label = "Jeton du bot Telegram"
|
||||
description = "De @BotFather sur Telegram (ex. 123456:ABC-DEF...). Le bot doit être administrateur du canal cible."
|
||||
|
||||
[i18n.fr.settings.telegram_chat_id]
|
||||
label = "ID de chat Telegram"
|
||||
description = "Canal : -100XXXXXXXXXX ou @nomducanal. Groupe : ID numérique. Obtenir via @userinfobot."
|
||||
|
||||
[i18n.fr.settings.whatsapp_token]
|
||||
label = "Jeton d'accès WhatsApp"
|
||||
description = "Jeton permanent depuis Meta Business Settings > Utilisateurs système. Les jetons temporaires expirent en 24h."
|
||||
|
||||
[i18n.fr.settings.whatsapp_phone_id]
|
||||
label = "ID de numéro de téléphone WhatsApp"
|
||||
description = "Depuis le Portail Développeurs Meta > WhatsApp > Configuration API (ex. 1234567890)"
|
||||
|
||||
[i18n.fr.settings.whatsapp_recipient]
|
||||
label = "Destinataire WhatsApp"
|
||||
description = "Numéro de téléphone au format international, sans + ni espaces (ex. 14155551234)"
|
||||
|
||||
[i18n.fr.settings.approval_mode]
|
||||
label = "Mode d'approbation"
|
||||
description = "Mettre les clips en file d'attente pour révision avant publication sur les canaux"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Videoclip-Hand"
|
||||
description = "Verwandelt lange Videos in virale Kurzclips mit Untertiteln und Vorschaubildern"
|
||||
category = "Inhalt"
|
||||
|
||||
[i18n.de.settings.stt_provider]
|
||||
label = "Sprache-zu-Text-Anbieter"
|
||||
description = "Methode der Audiotranskription für Untertitel und Clipauswahl"
|
||||
|
||||
[i18n.de.settings.tts_provider]
|
||||
label = "Text-zu-Sprache-Anbieter"
|
||||
description = "Optionale Voiceover- oder Erzählungsgenerierung für Clips"
|
||||
|
||||
[i18n.de.settings.elevenlabs_api_key]
|
||||
label = "ElevenLabs API-Schlüssel"
|
||||
description = "API-Schlüssel von elevenlabs.io für hochwertige Text-zu-Sprache. Erforderlich bei Auswahl von ElevenLabs TTS."
|
||||
|
||||
[i18n.de.settings.publish_target]
|
||||
label = "Veröffentlichungsziel"
|
||||
description = "Wohin fertige Clips nach der Verarbeitung gesendet werden. 'Nur lokal' wählen, um die Veröffentlichung zu überspringen."
|
||||
|
||||
[i18n.de.settings.telegram_bot_token]
|
||||
label = "Telegram-Bot-Token"
|
||||
description = "Von @BotFather auf Telegram (z.B. 123456:ABC-DEF...). Der Bot muss Administrator des Zielkanals sein."
|
||||
|
||||
[i18n.de.settings.telegram_chat_id]
|
||||
label = "Telegram-Chat-ID"
|
||||
description = "Kanal: -100XXXXXXXXXX oder @Kanalname. Gruppe: Numerische ID. Über @userinfobot abrufbar."
|
||||
|
||||
[i18n.de.settings.whatsapp_token]
|
||||
label = "WhatsApp-Zugriffstoken"
|
||||
description = "Permanentes Token aus Meta Business Settings > Systembenutzer. Temporäre Token laufen nach 24h ab."
|
||||
|
||||
[i18n.de.settings.whatsapp_phone_id]
|
||||
label = "WhatsApp-Telefonnummer-ID"
|
||||
description = "Aus dem Meta-Entwicklerportal > WhatsApp > API-Einrichtung (z.B. 1234567890)"
|
||||
|
||||
[i18n.de.settings.whatsapp_recipient]
|
||||
label = "WhatsApp-Empfänger"
|
||||
description = "Telefonnummer im internationalen Format, ohne + oder Leerzeichen (z.B. 14155551234)"
|
||||
|
||||
[i18n.de.settings.approval_mode]
|
||||
label = "Genehmigungsmodus"
|
||||
description = "Clips zur Überprüfung in die Warteschlange stellen, bevor sie auf Kanälen veröffentlicht werden"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "비디오 클립 Hand"
|
||||
description = "장편 영상을 자막과 썸네일이 포함된 바이럴 숏폼 클립으로 변환"
|
||||
category = "콘텐츠"
|
||||
|
||||
[i18n.ko.settings.stt_provider]
|
||||
label = "음성-텍스트 변환 서비스"
|
||||
description = "자막 생성 및 클립 선택을 위한 오디오 전사 방식"
|
||||
|
||||
[i18n.ko.settings.tts_provider]
|
||||
label = "텍스트-음성 변환 서비스"
|
||||
description = "선택적 더빙 또는 나레이션 생성 서비스"
|
||||
|
||||
[i18n.ko.settings.elevenlabs_api_key]
|
||||
label = "ElevenLabs API 키"
|
||||
description = "elevenlabs.io의 고품질 텍스트-음성 변환 API 키. ElevenLabs TTS 선택 시 필수."
|
||||
|
||||
[i18n.ko.settings.publish_target]
|
||||
label = "게시 대상"
|
||||
description = "처리 완료 후 숏폼 클립을 전송할 위치. '로컬 전용'을 선택하면 게시를 건너뜁니다."
|
||||
|
||||
[i18n.ko.settings.telegram_bot_token]
|
||||
label = "Telegram 봇 토큰"
|
||||
description = "Telegram의 @BotFather에서 발급 (예: 123456:ABC-DEF...). 봇이 대상 채널의 관리자여야 합니다."
|
||||
|
||||
[i18n.ko.settings.telegram_chat_id]
|
||||
label = "Telegram 채팅 ID"
|
||||
description = "채널: -100XXXXXXXXXX 또는 @채널명. 그룹: 숫자 ID. @userinfobot으로 확인 가능."
|
||||
|
||||
[i18n.ko.settings.whatsapp_token]
|
||||
label = "WhatsApp 액세스 토큰"
|
||||
description = "Meta 비즈니스 설정 > 시스템 사용자에서 발급한 영구 토큰. 임시 토큰은 24시간 후 만료."
|
||||
|
||||
[i18n.ko.settings.whatsapp_phone_id]
|
||||
label = "WhatsApp 전화번호 ID"
|
||||
description = "Meta 개발자 포털 > WhatsApp > API 설정에서 확인 (예: 1234567890)"
|
||||
|
||||
[i18n.ko.settings.whatsapp_recipient]
|
||||
label = "WhatsApp 수신자"
|
||||
description = "+ 기호나 공백 없이 국제 형식의 전화번호 (예: 14155551234)"
|
||||
|
||||
[i18n.ko.settings.approval_mode]
|
||||
label = "승인 모드"
|
||||
description = "채널에 게시하기 전 클립을 대기열에 추가하여 검토"
|
||||
+366
-12
@@ -182,6 +182,60 @@ description = "Analyze and track sentiment trends over time"
|
||||
setting_type = "toggle"
|
||||
default = "false"
|
||||
|
||||
[[settings]]
|
||||
key = "source_reliability_threshold"
|
||||
label = "Source Reliability Threshold"
|
||||
description = "Minimum source tier required to include a data point (lower tiers are discarded unless they are the sole source for a structural change)"
|
||||
setting_type = "select"
|
||||
default = "tier_3"
|
||||
|
||||
[[settings.options]]
|
||||
value = "tier_1"
|
||||
label = "Tier 1 only (official/primary sources)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "tier_2"
|
||||
label = "Tier 2+ (institutional and above)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "tier_3"
|
||||
label = "Tier 3+ (professional and above)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "tier_4"
|
||||
label = "Tier 4+ (community and above)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "tier_5"
|
||||
label = "All sources (no filtering)"
|
||||
|
||||
[[settings]]
|
||||
key = "change_significance_threshold"
|
||||
label = "Change Significance Threshold"
|
||||
description = "Minimum significance score (0-100) for a change to be classified as IMPORTANT. Changes below this threshold are classified as MINOR."
|
||||
setting_type = "select"
|
||||
default = "60"
|
||||
|
||||
[[settings.options]]
|
||||
value = "40"
|
||||
label = "40 (more sensitive — more alerts)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "50"
|
||||
label = "50 (balanced)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "60"
|
||||
label = "60 (default)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "70"
|
||||
label = "70 (stricter — fewer alerts)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "80"
|
||||
label = "80 (very strict — only critical-level)"
|
||||
|
||||
# ─── Agent configuration ─────────────────────────────────────────────────────
|
||||
|
||||
[agent]
|
||||
@@ -288,23 +342,40 @@ Relation types:
|
||||
|
||||
Compare current collection against previous state:
|
||||
1. Load `collector_knowledge_base.json` (previous snapshot)
|
||||
2. Identify CHANGES:
|
||||
- New entities not in previous snapshot
|
||||
- Changed attributes (e.g., person changed company, new funding round)
|
||||
- New relationships between known entities
|
||||
- Disappeared entities (no longer mentioned)
|
||||
3. Score each change by significance (critical/important/minor):
|
||||
- Critical: leadership change, acquisition, major funding, product launch
|
||||
- Important: new partnership, hiring surge, pricing change, competitor move
|
||||
- Minor: blog post, minor update, mention in article
|
||||
2. Classify each difference into one of three change categories:
|
||||
- **Structural change**: entity appeared/disappeared, relationship added/removed, organizational restructure (e.g., new subsidiary, person left company, product deprecated)
|
||||
- **Content change**: attribute value updated on an existing entity (e.g., funding amount increased, role title changed, version number bumped, pricing modified)
|
||||
- **Metadata change**: source count changed, confidence level shifted, last_seen timestamp updated, but the core fact is unchanged
|
||||
|
||||
If `alert_on_changes` is enabled and critical changes found:
|
||||
- event_publish with change summary
|
||||
3. Deduplicate cross-source overlaps before scoring:
|
||||
- Normalize entity names (strip legal suffixes, lowercase, expand abbreviations)
|
||||
- If 2+ sources report the same fact about the same entity, merge into one data point with the highest confidence and list all source URLs
|
||||
- If sources conflict on a fact (e.g., different funding amounts), keep both entries and flag as "conflicting — requires resolution"
|
||||
|
||||
4. Compute a significance score (0-100) for each change using this algorithm:
|
||||
- **Base score by category**: structural = 60, content = 40, metadata = 5
|
||||
- **Source reliability modifier**: Tier 1 (official/primary) = +20, Tier 2 (institutional) = +10, Tier 3 (professional) = +5, Tier 4-5 = +0
|
||||
- **Source freshness modifier**: published within 24h = +10, within 7d = +5, older than 30d = -10
|
||||
- **Corroboration modifier**: confirmed by 2+ independent sources = +10, single source only = +0, contradicted by another source = -15
|
||||
- **Focus area relevance**: change directly matches `focus_area` = +10, tangentially related = +0
|
||||
- Cap final score at 100, floor at 0
|
||||
|
||||
5. Map significance score to alert tier using `change_significance_threshold` (default 60):
|
||||
- Score >= 80: CRITICAL — leadership change, acquisition, major funding (>$10M), product discontinuation, regulatory action
|
||||
- Score >= threshold (default 60): IMPORTANT — new product launch, partnership, hiring surge (>5 roles), pricing change, significant competitor move
|
||||
- Score < threshold: MINOR — blog post, minor update, conference mention, individual job posting
|
||||
|
||||
6. Filter sources by `source_reliability_threshold` (default "tier_3"):
|
||||
- Discard data points where ALL supporting sources fall below the configured threshold tier
|
||||
- Exception: if a below-threshold source is the ONLY source for a structural change, keep it but downgrade confidence to "low" and flag for corroboration in the next cycle
|
||||
|
||||
If `alert_on_changes` is enabled and any change scores CRITICAL:
|
||||
- event_publish with change summary including: entity name, change category, significance score, top source URL
|
||||
|
||||
If `track_sentiment` is enabled:
|
||||
- Classify each source as positive/negative/neutral toward the target
|
||||
- Track sentiment trend vs previous cycle
|
||||
- Note significant sentiment shifts in the report
|
||||
- Note significant sentiment shifts (score delta > 2 in one cycle) in the report
|
||||
|
||||
---
|
||||
|
||||
@@ -391,6 +462,289 @@ token_consumption = "high"
|
||||
default_active = false
|
||||
activation_warning = "Collector hand runs continuously and monitors targets, consuming tokens."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "情报采集 Hand"
|
||||
description = "自主情报采集智能体——持续监控目标,支持变更检测和知识图谱"
|
||||
category = "数据"
|
||||
|
||||
[i18n.zh.settings.target_subject]
|
||||
label = "监控目标"
|
||||
description = "要监控的对象(公司名称、人物、技术、市场、话题)"
|
||||
|
||||
[i18n.zh.settings.collection_depth]
|
||||
label = "采集深度"
|
||||
description = "每个采集周期的挖掘深度"
|
||||
|
||||
[i18n.zh.settings.update_frequency]
|
||||
label = "更新频率"
|
||||
description = "执行采集扫描的频率"
|
||||
|
||||
[i18n.zh.settings.focus_area]
|
||||
label = "关注领域"
|
||||
description = "分析采集情报时的侧重角度"
|
||||
|
||||
[i18n.zh.settings.alert_on_changes]
|
||||
label = "变更告警"
|
||||
description = "检测到重大变更时发布事件通知"
|
||||
|
||||
[i18n.zh.settings.report_format]
|
||||
label = "报告格式"
|
||||
description = "情报报告的输出格式"
|
||||
|
||||
[i18n.zh.settings.max_sources_per_cycle]
|
||||
label = "每周期最大来源数"
|
||||
description = "每次采集扫描处理的最大来源数量"
|
||||
|
||||
[i18n.zh.settings.track_sentiment]
|
||||
label = "情感追踪"
|
||||
description = "分析并追踪随时间变化的情感趋势"
|
||||
|
||||
[i18n.zh.settings.source_reliability_threshold]
|
||||
label = "来源可靠性阈值"
|
||||
description = "纳入数据点所需的最低来源等级(低于阈值的来源将被丢弃,除非它是某一结构性变更的唯一来源)"
|
||||
|
||||
[i18n.zh.settings.change_significance_threshold]
|
||||
label = "变更显著性阈值"
|
||||
description = "变更被归类为「重要」的最低显著性分数(0-100),低于此阈值的变更归类为「次要」"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "インテリジェンス収集 Hand"
|
||||
description = "自律型インテリジェンス収集エージェント——変更検出とナレッジグラフによる対象の継続的監視"
|
||||
category = "データ"
|
||||
|
||||
[i18n.ja.settings.target_subject]
|
||||
label = "監視対象"
|
||||
description = "監視する対象(企業名、人物、技術、市場、トピック)"
|
||||
|
||||
[i18n.ja.settings.collection_depth]
|
||||
label = "収集深度"
|
||||
description = "各収集サイクルでの調査の深さ"
|
||||
|
||||
[i18n.ja.settings.update_frequency]
|
||||
label = "更新頻度"
|
||||
description = "収集スキャンの実行頻度"
|
||||
|
||||
[i18n.ja.settings.focus_area]
|
||||
label = "フォーカスエリア"
|
||||
description = "収集したインテリジェンスを分析する際の視点"
|
||||
|
||||
[i18n.ja.settings.alert_on_changes]
|
||||
label = "変更アラート"
|
||||
description = "重大な変更が検出された場合にイベント通知を発行する"
|
||||
|
||||
[i18n.ja.settings.report_format]
|
||||
label = "レポート形式"
|
||||
description = "インテリジェンスレポートの出力形式"
|
||||
|
||||
[i18n.ja.settings.max_sources_per_cycle]
|
||||
label = "サイクルあたりの最大ソース数"
|
||||
description = "各収集スキャンで処理するソースの最大数"
|
||||
|
||||
[i18n.ja.settings.track_sentiment]
|
||||
label = "センチメント追跡"
|
||||
description = "時間の経過に伴うセンチメントの傾向を分析・追跡する"
|
||||
|
||||
[i18n.ja.settings.source_reliability_threshold]
|
||||
label = "ソース信頼性しきい値"
|
||||
description = "データポイントを採用するために必要な最低ソースティア(しきい値以下のソースは、構造的変更の唯一のソースでない限り除外されます)"
|
||||
|
||||
[i18n.ja.settings.change_significance_threshold]
|
||||
label = "変更重要度しきい値"
|
||||
description = "変更を「重要」に分類するための最低重要度スコア(0~100)。このしきい値以下の変更は「軽微」に分類されます"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Recopilación de Inteligencia"
|
||||
description = "Recopilador autónomo de inteligencia — monitorea cualquier objetivo de forma continua con detección de cambios y grafos de conocimiento"
|
||||
category = "Datos"
|
||||
|
||||
[i18n.es.settings.target_subject]
|
||||
label = "Objetivo de monitoreo"
|
||||
description = "Qué monitorear (nombre de empresa, persona, tecnología, mercado, tema)"
|
||||
|
||||
[i18n.es.settings.collection_depth]
|
||||
label = "Profundidad de recopilación"
|
||||
description = "Qué tan profundo investigar en cada ciclo"
|
||||
|
||||
[i18n.es.settings.update_frequency]
|
||||
label = "Frecuencia de actualización"
|
||||
description = "Con qué frecuencia ejecutar los barridos de recopilación"
|
||||
|
||||
[i18n.es.settings.focus_area]
|
||||
label = "Área de enfoque"
|
||||
description = "Perspectiva desde la cual analizar la inteligencia recopilada"
|
||||
|
||||
[i18n.es.settings.alert_on_changes]
|
||||
label = "Alertar ante cambios"
|
||||
description = "Publicar un evento cuando se detecten cambios significativos"
|
||||
|
||||
[i18n.es.settings.report_format]
|
||||
label = "Formato de informe"
|
||||
description = "Formato de salida para los informes de inteligencia"
|
||||
|
||||
[i18n.es.settings.max_sources_per_cycle]
|
||||
label = "Máximo de fuentes por ciclo"
|
||||
description = "Número máximo de fuentes a procesar por barrido de recopilación"
|
||||
|
||||
[i18n.es.settings.track_sentiment]
|
||||
label = "Seguimiento de sentimiento"
|
||||
description = "Analizar y rastrear las tendencias de sentimiento a lo largo del tiempo"
|
||||
|
||||
[i18n.es.settings.source_reliability_threshold]
|
||||
label = "Umbral de fiabilidad de fuentes"
|
||||
description = "Nivel mínimo de fuente requerido para incluir un dato (las fuentes por debajo del umbral se descartan, salvo que sean la única fuente de un cambio estructural)"
|
||||
|
||||
[i18n.es.settings.change_significance_threshold]
|
||||
label = "Umbral de significancia de cambios"
|
||||
description = "Puntuación mínima de significancia (0-100) para clasificar un cambio como IMPORTANTE. Los cambios por debajo se clasifican como MENORES."
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand Collecteur de Renseignements"
|
||||
description = "Collecteur autonome de renseignements — surveille toute cible en continu avec détection de changements et graphes de connaissances"
|
||||
category = "Données"
|
||||
|
||||
[i18n.fr.settings.target_subject]
|
||||
label = "Sujet cible"
|
||||
description = "Objet de la surveillance (nom d'entreprise, personne, technologie, marché, sujet)"
|
||||
|
||||
[i18n.fr.settings.collection_depth]
|
||||
label = "Profondeur de collecte"
|
||||
description = "Niveau d'approfondissement à chaque cycle de collecte"
|
||||
|
||||
[i18n.fr.settings.update_frequency]
|
||||
label = "Fréquence de mise à jour"
|
||||
description = "Fréquence d'exécution des cycles de collecte"
|
||||
|
||||
[i18n.fr.settings.focus_area]
|
||||
label = "Domaine d'intérêt"
|
||||
description = "Angle d'analyse des renseignements collectés"
|
||||
|
||||
[i18n.fr.settings.alert_on_changes]
|
||||
label = "Alerte sur changements"
|
||||
description = "Publier un événement lorsque des changements significatifs sont détectés"
|
||||
|
||||
[i18n.fr.settings.report_format]
|
||||
label = "Format de rapport"
|
||||
description = "Format de sortie pour les rapports de renseignements"
|
||||
|
||||
[i18n.fr.settings.max_sources_per_cycle]
|
||||
label = "Sources maximum par cycle"
|
||||
description = "Nombre maximum de sources à traiter par cycle de collecte"
|
||||
|
||||
[i18n.fr.settings.track_sentiment]
|
||||
label = "Suivi du sentiment"
|
||||
description = "Analyser et suivre les tendances de sentiment au fil du temps"
|
||||
|
||||
[i18n.fr.settings.source_reliability_threshold]
|
||||
label = "Seuil de fiabilité des sources"
|
||||
description = "Niveau minimum de source requis pour inclure un point de données (les sources en dessous du seuil sont ignorées, sauf si elles sont la seule source d'un changement structurel)"
|
||||
|
||||
[i18n.fr.settings.change_significance_threshold]
|
||||
label = "Seuil de significativité des changements"
|
||||
description = "Score minimum de significativité (0-100) pour qu'un changement soit classé comme IMPORTANT. Les changements en dessous sont classés comme MINEURS."
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Informationssammlungs-Hand"
|
||||
description = "Autonomer Informationssammler — überwacht jedes Ziel kontinuierlich mit Änderungserkennung und Wissensgraphen"
|
||||
category = "Daten"
|
||||
|
||||
[i18n.de.settings.target_subject]
|
||||
label = "Zielobjekt"
|
||||
description = "Was überwacht werden soll (Firmenname, Person, Technologie, Markt, Thema)"
|
||||
|
||||
[i18n.de.settings.collection_depth]
|
||||
label = "Sammlungstiefe"
|
||||
description = "Wie tief in jedem Sammlungszyklus recherchiert wird"
|
||||
|
||||
[i18n.de.settings.update_frequency]
|
||||
label = "Aktualisierungshäufigkeit"
|
||||
description = "Wie oft Sammlungszyklen ausgeführt werden"
|
||||
|
||||
[i18n.de.settings.focus_area]
|
||||
label = "Fokusbereich"
|
||||
description = "Perspektive für die Analyse der gesammelten Informationen"
|
||||
|
||||
[i18n.de.settings.alert_on_changes]
|
||||
label = "Warnung bei Änderungen"
|
||||
description = "Ein Ereignis veröffentlichen, wenn bedeutende Änderungen erkannt werden"
|
||||
|
||||
[i18n.de.settings.report_format]
|
||||
label = "Berichtsformat"
|
||||
description = "Ausgabeformat für Informationsberichte"
|
||||
|
||||
[i18n.de.settings.max_sources_per_cycle]
|
||||
label = "Maximale Quellen pro Zyklus"
|
||||
description = "Maximale Anzahl der pro Sammlungszyklus zu verarbeitenden Quellen"
|
||||
|
||||
[i18n.de.settings.track_sentiment]
|
||||
label = "Stimmungsverfolgung"
|
||||
description = "Stimmungstrends im Zeitverlauf analysieren und verfolgen"
|
||||
|
||||
[i18n.de.settings.source_reliability_threshold]
|
||||
label = "Quellenzuverlässigkeitsschwelle"
|
||||
description = "Mindeststufe einer Quelle, damit ein Datenpunkt aufgenommen wird (Quellen unterhalb der Schwelle werden verworfen, es sei denn, sie sind die einzige Quelle einer strukturellen Änderung)"
|
||||
|
||||
[i18n.de.settings.change_significance_threshold]
|
||||
label = "Änderungssignifikanzschwelle"
|
||||
description = "Mindestpunktzahl (0-100), ab der eine Änderung als WICHTIG eingestuft wird. Änderungen unterhalb werden als GERINGFÜGIG eingestuft."
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "정보 수집 Hand"
|
||||
description = "자율 정보 수집 에이전트 — 대상을 지속적으로 모니터링하며 변경 감지 및 지식 그래프 지원"
|
||||
category = "데이터"
|
||||
|
||||
[i18n.ko.settings.target_subject]
|
||||
label = "모니터링 대상"
|
||||
description = "모니터링할 대상 (회사명, 인물, 기술, 시장, 주제)"
|
||||
|
||||
[i18n.ko.settings.collection_depth]
|
||||
label = "수집 깊이"
|
||||
description = "각 수집 주기의 조사 깊이"
|
||||
|
||||
[i18n.ko.settings.update_frequency]
|
||||
label = "업데이트 빈도"
|
||||
description = "수집 스캔 실행 주기"
|
||||
|
||||
[i18n.ko.settings.focus_area]
|
||||
label = "관심 분야"
|
||||
description = "수집된 정보를 분석하는 관점"
|
||||
|
||||
[i18n.ko.settings.alert_on_changes]
|
||||
label = "변경 알림"
|
||||
description = "중요한 변경 사항 감지 시 이벤트 알림 발행"
|
||||
|
||||
[i18n.ko.settings.report_format]
|
||||
label = "보고서 형식"
|
||||
description = "정보 보고서의 출력 형식"
|
||||
|
||||
[i18n.ko.settings.max_sources_per_cycle]
|
||||
label = "주기당 최대 소스 수"
|
||||
description = "수집 스캔당 처리할 최대 소스 수"
|
||||
|
||||
[i18n.ko.settings.track_sentiment]
|
||||
label = "감성 추적"
|
||||
description = "시간에 따른 감성 추세 분석 및 추적"
|
||||
|
||||
[i18n.ko.settings.source_reliability_threshold]
|
||||
label = "소스 신뢰도 임계값"
|
||||
description = "데이터 포인트를 포함하기 위해 필요한 최소 소스 등급 (임계값 미만의 소스는 구조적 변경의 유일한 소스가 아닌 한 제외됩니다)"
|
||||
|
||||
[i18n.ko.settings.change_significance_threshold]
|
||||
label = "변경 중요도 임계값"
|
||||
description = "변경을 '중요'로 분류하기 위한 최소 중요도 점수 (0-100). 이 임계값 미만의 변경은 '경미'로 분류됩니다"
|
||||
+810
-32
@@ -150,45 +150,82 @@ site:sec.gov "[company]"
|
||||
|
||||
## Change Detection Methodology
|
||||
|
||||
### Snapshot Comparison
|
||||
1. Store the current state of all entities as a JSON snapshot
|
||||
2. On next collection cycle, compare new state against previous snapshot
|
||||
3. Classify changes:
|
||||
### Change Classification
|
||||
|
||||
| Change Type | Significance | Example |
|
||||
|-------------|-------------|---------|
|
||||
| Entity appeared | Varies | New competitor enters market |
|
||||
| Entity disappeared | Important | Company goes quiet, product deprecated |
|
||||
| Attribute changed | Critical-Minor | CEO changed (critical), address changed (minor) |
|
||||
| New relation | Important | New partnership, acquisition, hiring |
|
||||
| Relation removed | Important | Person left company, partnership ended |
|
||||
| Sentiment shift | Important | Positive→Negative media coverage |
|
||||
Every difference between the current snapshot and the previous one falls into exactly one category:
|
||||
|
||||
| Category | Definition | Examples |
|
||||
|----------|-----------|---------|
|
||||
| **Structural** | Entity appeared/disappeared, relationship added/removed | New competitor enters market, person left company, product deprecated, new partnership formed |
|
||||
| **Content** | Attribute value changed on an existing entity | CEO changed, funding amount updated, version number bumped, pricing modified |
|
||||
| **Metadata** | Supporting data changed but core fact is the same | New source confirms existing fact, confidence upgraded, last_seen timestamp refreshed |
|
||||
|
||||
### Cross-Source Deduplication
|
||||
|
||||
Before scoring, deduplicate overlapping data points:
|
||||
1. **Normalize** entity names: strip legal suffixes (Inc, LLC, Corp), lowercase, expand common abbreviations
|
||||
2. **Merge** when 2+ sources report the same fact about the same entity — keep highest confidence, list all source URLs
|
||||
3. **Flag conflicts** when sources disagree on a fact (e.g., different funding amounts) — record both, mark as "conflicting — requires resolution"
|
||||
|
||||
### Significance Scoring Algorithm
|
||||
|
||||
Compute a numeric score (0-100) for each change:
|
||||
|
||||
### Significance Scoring
|
||||
```
|
||||
CRITICAL (immediate alert):
|
||||
- Leadership change (CEO, CTO, board)
|
||||
- Acquisition or merger
|
||||
- Major funding round (>$10M)
|
||||
- Product discontinuation
|
||||
- Legal action or regulatory issue
|
||||
Base score (by category):
|
||||
Structural change = 60
|
||||
Content change = 40
|
||||
Metadata change = 5
|
||||
|
||||
IMPORTANT (include in next report):
|
||||
- New product launch
|
||||
- New partnership or integration
|
||||
- Hiring surge (>5 roles)
|
||||
- Pricing change
|
||||
- Competitor move
|
||||
- Major customer win/loss
|
||||
Source reliability modifier (best source tier for this data point):
|
||||
Tier 1 (official/primary) = +20
|
||||
Tier 2 (institutional) = +10
|
||||
Tier 3 (professional) = +5
|
||||
Tier 4-5 (community/anon) = +0
|
||||
|
||||
MINOR (note in report):
|
||||
- Blog post or press mention
|
||||
- Minor update or patch
|
||||
- Social media activity spike
|
||||
- Conference appearance
|
||||
- Job posting (individual)
|
||||
Source freshness modifier (publication age):
|
||||
Within 24 hours = +10
|
||||
Within 7 days = +5
|
||||
Within 30 days = +0
|
||||
Older than 30 days = -10
|
||||
|
||||
Corroboration modifier:
|
||||
Confirmed by 2+ independent sources = +10
|
||||
Single source only = +0
|
||||
Contradicted by another source = -15
|
||||
|
||||
Focus area relevance:
|
||||
Directly matches configured focus_area = +10
|
||||
Tangentially related = +0
|
||||
|
||||
Final score = clamp(base + reliability + freshness + corroboration + relevance, 0, 100)
|
||||
```
|
||||
|
||||
### Alert Tier Mapping
|
||||
|
||||
Map the computed significance score to an action tier using `change_significance_threshold` (configurable, default 60):
|
||||
|
||||
```
|
||||
Score >= 80 → CRITICAL (immediate alert via event_publish)
|
||||
Examples: leadership change (CEO/CTO/CFO), acquisition or merger,
|
||||
major funding round (>$10M), product discontinuation,
|
||||
regulatory action, data breach
|
||||
|
||||
Score >= threshold → IMPORTANT (include in next report)
|
||||
Examples: new product launch, new partnership, hiring surge (>5 roles),
|
||||
pricing change, significant competitor move, major customer win/loss
|
||||
|
||||
Score < threshold → MINOR (note in report)
|
||||
Examples: blog post, minor update or patch, conference appearance,
|
||||
individual job posting, social media activity within normal range
|
||||
```
|
||||
|
||||
### Source Reliability Filtering
|
||||
|
||||
Apply the configured `source_reliability_threshold` (default: tier_3) to filter low-quality data:
|
||||
- **Discard** data points where ALL supporting sources fall below the threshold tier
|
||||
- **Exception**: if a below-threshold source is the ONLY source for a structural change, keep it but downgrade confidence to "low" and flag for corroboration in the next cycle
|
||||
|
||||
---
|
||||
|
||||
## Sentiment Analysis Heuristics
|
||||
@@ -269,3 +306,744 @@ Before including data in the knowledge graph, evaluate:
|
||||
6. **Track record**: Has this source been reliable in the past?
|
||||
|
||||
If a claim fails 3+ checks, downgrade its confidence to "low".
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Competitor Monitoring Campaign
|
||||
|
||||
**Scenario**: A B2B SaaS company wants continuous intelligence on three direct competitors: AlphaCloud, BetaStack, and GammaSuite.
|
||||
|
||||
**Step 1 — Define targets and collection requirements**
|
||||
|
||||
Configure the hand with:
|
||||
```
|
||||
target_subject: "AlphaCloud, BetaStack, GammaSuite"
|
||||
focus_area: competitor
|
||||
collection_depth: deep
|
||||
update_frequency: daily
|
||||
alert_on_changes: true
|
||||
track_sentiment: true
|
||||
max_sources_per_cycle: 50
|
||||
```
|
||||
|
||||
Build the initial query set:
|
||||
```
|
||||
"AlphaCloud" pricing OR plans OR tiers
|
||||
"AlphaCloud" product launch OR release OR update
|
||||
"AlphaCloud" review site:g2.com OR site:capterra.com
|
||||
"AlphaCloud" customer case study
|
||||
"AlphaCloud" hiring site:linkedin.com OR site:greenhouse.io
|
||||
"switch from AlphaCloud to"
|
||||
(repeat for BetaStack and GammaSuite)
|
||||
```
|
||||
|
||||
**Step 2 — Run first collection cycle**
|
||||
|
||||
Execute queries, fetch top results, extract entities:
|
||||
```json
|
||||
[
|
||||
{"type": "product", "name": "AlphaCloud v4.2", "company": "AlphaCloud", "launch_date": "2025-11-15", "source": "alphacloud.com/blog"},
|
||||
{"type": "person", "name": "Sarah Chen", "role": "New VP Engineering", "company": "BetaStack", "source": "linkedin.com/in/sarachen"},
|
||||
{"type": "event", "name": "GammaSuite Series C", "amount": "$85M", "date": "2025-11-10", "source": "techcrunch.com/2025/11/10/gammasuite-series-c"}
|
||||
]
|
||||
```
|
||||
|
||||
**Step 3 — Build knowledge graph entries**
|
||||
|
||||
```
|
||||
knowledge_add_entity type=company name="AlphaCloud" industry="SaaS" funding_stage="Series B"
|
||||
knowledge_add_entity type=product name="AlphaCloud v4.2" category="cloud platform"
|
||||
knowledge_add_entity type=person name="Sarah Chen" role="VP Engineering" company="BetaStack"
|
||||
knowledge_add_relation source="AlphaCloud" relation="launched" target="AlphaCloud v4.2"
|
||||
knowledge_add_relation source="Sarah Chen" relation="works_at" target="BetaStack"
|
||||
```
|
||||
|
||||
**Step 4 — Process findings into change detection**
|
||||
|
||||
| Change | Type | Significance | Action |
|
||||
|--------|------|-------------|--------|
|
||||
| AlphaCloud released v4.2 with AI features | Product launch | IMPORTANT | Include in report, compare against own roadmap |
|
||||
| BetaStack hired VP Engineering from FAANG | Leadership change | IMPORTANT | Track subsequent hiring patterns |
|
||||
| GammaSuite raised $85M Series C | Major funding | CRITICAL | Immediate alert, expect aggressive expansion |
|
||||
|
||||
**Step 5 — Generate intelligence brief**
|
||||
|
||||
```markdown
|
||||
# Competitor Intelligence Brief
|
||||
**Date**: 2025-11-16 | **Cycle**: 1 | **Sources**: 47
|
||||
|
||||
## Priority Changes
|
||||
1. [CRITICAL] GammaSuite closed $85M Series C led by Sequoia (TechCrunch, confirmed via Crunchbase)
|
||||
2. [IMPORTANT] AlphaCloud shipped v4.2 with AI-assisted workflow builder
|
||||
3. [IMPORTANT] BetaStack hired Sarah Chen (ex-Google) as VP Engineering
|
||||
|
||||
## Executive Summary
|
||||
GammaSuite's large funding round signals intent to accelerate growth — expect increased
|
||||
marketing spend and possible M&A activity in the next 6 months. AlphaCloud's v4.2
|
||||
introduces direct feature overlap with our AI pipeline. BetaStack's engineering
|
||||
leadership hire suggests a product quality push.
|
||||
|
||||
## Recommended Actions
|
||||
- Review AlphaCloud v4.2 feature parity against our roadmap
|
||||
- Monitor GammaSuite job postings for expansion signals
|
||||
- Track BetaStack engineering team growth over next 3 cycles
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Technology Landscape Mapping
|
||||
|
||||
**Scenario**: Map the emerging real-time AI inference landscape — track frameworks, adoption signals, key players, and performance benchmarks.
|
||||
|
||||
**Step 1 — Define scope and seed entities**
|
||||
|
||||
```
|
||||
target_subject: "real-time AI inference (vLLM, TensorRT-LLM, Triton, Ollama, llama.cpp)"
|
||||
focus_area: technology
|
||||
collection_depth: exhaustive
|
||||
update_frequency: weekly
|
||||
```
|
||||
|
||||
Initial seed queries:
|
||||
```
|
||||
"real-time AI inference" benchmark 2025
|
||||
"vLLM" vs "TensorRT-LLM" performance
|
||||
"llama.cpp" release changelog
|
||||
"AI inference" startup funding 2025
|
||||
"edge AI inference" adoption enterprise
|
||||
"AI inference" tokens per second benchmark
|
||||
site:github.com "vLLM" stars OR contributors
|
||||
site:arxiv.org "inference optimization" 2025
|
||||
```
|
||||
|
||||
**Step 2 — Build entity graph from first sweep**
|
||||
|
||||
Entities collected:
|
||||
```json
|
||||
[
|
||||
{"type": "technology", "name": "vLLM", "version": "0.6.3", "vendor": "UC Berkeley / community", "category": "inference engine"},
|
||||
{"type": "technology", "name": "TensorRT-LLM", "version": "0.15", "vendor": "NVIDIA", "category": "inference engine"},
|
||||
{"type": "company", "name": "Groq", "industry": "AI hardware", "product": "LPU Inference Engine"},
|
||||
{"type": "number", "metric": "tokens_per_second", "value": 523, "context": "Groq Llama 3 70B", "date": "2025-10"},
|
||||
{"type": "number", "metric": "github_stars", "value": 32400, "context": "vLLM", "date": "2025-11"}
|
||||
]
|
||||
```
|
||||
|
||||
Relationships:
|
||||
```
|
||||
vLLM --competes_with--> TensorRT-LLM
|
||||
vLLM --competes_with--> Ollama
|
||||
Groq --launched--> "LPU Inference Engine"
|
||||
NVIDIA --launched--> TensorRT-LLM
|
||||
llama.cpp --uses--> GGUF format
|
||||
```
|
||||
|
||||
**Step 3 — Track adoption signals across cycles**
|
||||
|
||||
| Signal Type | What to Watch | Detection Method |
|
||||
|-------------|--------------|-----------------|
|
||||
| GitHub velocity | Stars, forks, contributor count week-over-week | Snapshot comparison |
|
||||
| Enterprise adoption | Case studies, "we migrated to X" blog posts | Keyword search |
|
||||
| Benchmark results | Tokens/sec, latency, cost-per-token comparisons | Structured extraction |
|
||||
| Job postings | "Experience with vLLM" in job descriptions | Job board queries |
|
||||
| Conference talks | Accepted papers, keynote mentions | Conference program search |
|
||||
|
||||
**Step 4 — Detect trends over 4 weekly cycles**
|
||||
|
||||
```
|
||||
Cycle 1: vLLM 31,800 stars | TensorRT-LLM 9,200 stars | Ollama 98,000 stars
|
||||
Cycle 2: vLLM 32,400 stars | TensorRT-LLM 9,500 stars | Ollama 101,000 stars
|
||||
Cycle 3: vLLM 33,500 stars | TensorRT-LLM 9,600 stars | Ollama 103,500 stars
|
||||
Cycle 4: vLLM 35,200 stars | TensorRT-LLM 9,700 stars | Ollama 105,000 stars
|
||||
|
||||
Trend: vLLM accelerating (+1,700/wk avg → +1,700 last week)
|
||||
Ollama decelerating (+3,000/wk → +1,500/wk)
|
||||
TensorRT-LLM flat (~200/wk)
|
||||
```
|
||||
|
||||
**Step 5 — Produce technology landscape report**
|
||||
|
||||
Include a positioning summary:
|
||||
|
||||
| Framework | Strengths | Weaknesses | Momentum | Best For |
|
||||
|-----------|-----------|------------|----------|----------|
|
||||
| vLLM | High throughput, PagedAttention | GPU-only, complex setup | Accelerating | Production serving at scale |
|
||||
| TensorRT-LLM | NVIDIA optimization, low latency | Vendor lock-in, NVIDIA GPUs only | Flat | NVIDIA-stack deployments |
|
||||
| Ollama | Simple UX, local-first | Lower throughput, less tunable | Decelerating | Developer experimentation |
|
||||
| llama.cpp | CPU support, portable | Manual optimization needed | Steady | Edge/embedded inference |
|
||||
| Groq LPU | Extreme speed, low latency | Limited model support, cloud-only | Growing | Latency-critical applications |
|
||||
|
||||
---
|
||||
|
||||
### Example 3: M&A Signal Detection
|
||||
|
||||
**Scenario**: Detect early acquisition indicators for companies in the enterprise observability space (Datadog, Grafana Labs, Chronosphere, Honeycomb).
|
||||
|
||||
**Step 1 — Define M&A signal categories**
|
||||
|
||||
| Signal Category | Indicators | Weight |
|
||||
|----------------|-----------|--------|
|
||||
| Executive changes | CEO/CFO departure, new "Chief Strategy Officer", board additions | High |
|
||||
| Hiring patterns | Sudden corporate development/M&A roles, legal team expansion | High |
|
||||
| Financial signals | Unusual funding, secondary sales, down round, runway concerns | High |
|
||||
| Strategic moves | Exclusive partnerships, technology licensing, IP transfers | Medium |
|
||||
| Market behavior | Quiet period (no product updates), website changes, domain changes | Medium |
|
||||
| Social signals | Founder tone shifts, "exciting news soon" posts, unusual silence | Low |
|
||||
|
||||
**Step 2 — Build targeted queries**
|
||||
|
||||
```
|
||||
"Chronosphere" AND ("acquisition" OR "acquire" OR "acqui-hire" OR "merger")
|
||||
"Honeycomb" AND ("strategic alternatives" OR "exploring options" OR "advisors")
|
||||
"Grafana Labs" AND ("corporate development" OR "M&A" OR "strategic partnership")
|
||||
site:linkedin.com "Chronosphere" "corporate development" OR "M&A"
|
||||
site:sec.gov "Honeycomb" OR "Hound Technology"
|
||||
"[company]" "quiet period" OR "exciting announcement"
|
||||
"[company]" hiring "corporate development" OR "business development director"
|
||||
"[company]" board of directors new appointment
|
||||
```
|
||||
|
||||
**Step 3 — Entity and event extraction**
|
||||
|
||||
From collected sources, extract and classify:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "event",
|
||||
"name": "Chronosphere CFO departure",
|
||||
"date": "2025-10-28",
|
||||
"entities": ["Chronosphere", "Lisa Park"],
|
||||
"signal_category": "executive_change",
|
||||
"m_and_a_weight": "high",
|
||||
"source": "linkedin.com/posts/lisapark-farewell"
|
||||
},
|
||||
{
|
||||
"type": "event",
|
||||
"name": "Honeycomb hires Goldman Sachs advisor",
|
||||
"date": "2025-11-02",
|
||||
"entities": ["Honeycomb", "Goldman Sachs"],
|
||||
"signal_category": "financial",
|
||||
"m_and_a_weight": "high",
|
||||
"source": "theinformation.com/articles/honeycomb-advisors"
|
||||
},
|
||||
{
|
||||
"type": "event",
|
||||
"name": "Datadog acquires incident.io",
|
||||
"date": "2025-11-08",
|
||||
"entities": ["Datadog", "incident.io"],
|
||||
"signal_category": "strategic",
|
||||
"m_and_a_weight": "confirmed_event",
|
||||
"source": "datadog.com/blog/incident-io-acquisition"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Step 4 — Score composite M&A probability**
|
||||
|
||||
Aggregate signals per company over a rolling 90-day window:
|
||||
|
||||
```
|
||||
Chronosphere:
|
||||
- CFO departed (high) +3
|
||||
- 2 corp dev job postings +2
|
||||
- No product release in 90d +1
|
||||
- Composite score: 6/10 → ELEVATED
|
||||
|
||||
Honeycomb:
|
||||
- Hired investment bank +4
|
||||
- Board added PE partner +2
|
||||
- Founder "grateful" post +1
|
||||
- Composite score: 7/10 → HIGH
|
||||
|
||||
Grafana Labs:
|
||||
- New enterprise partnerships +1
|
||||
- Active hiring across all -1 (normal growth, reduces M&A signal)
|
||||
- Composite score: 0/10 → LOW
|
||||
```
|
||||
|
||||
**Step 5 — Generate M&A signal alert**
|
||||
|
||||
```markdown
|
||||
# M&A Signal Alert: Enterprise Observability Sector
|
||||
**Date**: 2025-11-10 | **Window**: 90 days
|
||||
|
||||
## HIGH probability
|
||||
- **Honeycomb**: Investment bank engagement + board changes suggest active process.
|
||||
Key evidence: Goldman Sachs advisory (The Information), new PE board member.
|
||||
Likely acquirers: Datadog, Cisco, ServiceNow.
|
||||
|
||||
## ELEVATED probability
|
||||
- **Chronosphere**: Leadership turnover + hiring freeze + corp dev roles.
|
||||
Key evidence: CFO departure, no product releases, corp dev postings on LinkedIn.
|
||||
Could indicate: acquisition target OR internal restructuring.
|
||||
|
||||
## LOW probability
|
||||
- **Grafana Labs**: Normal operating patterns, active hiring, regular releases.
|
||||
- **Datadog**: Active acquirer (incident.io deal closed), not a target.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Entity Extraction
|
||||
|
||||
### Relationship Mapping from Unstructured Text
|
||||
|
||||
Extract relationships by identifying sentence-level patterns that connect two named entities.
|
||||
|
||||
**Pattern templates**:
|
||||
```
|
||||
[Person] joined [Company] as [Role]
|
||||
→ relation: works_at, attributes: {role: Role, event: "joined"}
|
||||
|
||||
[Company] acquired [Company] for [Amount]
|
||||
→ relation: acquired, attributes: {amount: Amount}
|
||||
|
||||
[Person] and [Person] co-founded [Company]
|
||||
→ relations: founded (x2), co_founded_with (between persons)
|
||||
|
||||
[Company] partnered with [Company] to [Purpose]
|
||||
→ relation: partnered_with, attributes: {purpose: Purpose}
|
||||
|
||||
[Person] left [Company] to join [Company]
|
||||
→ relation: left (old), works_at (new), attributes: {event: "departure"}
|
||||
```
|
||||
|
||||
**Multi-hop relationships**: When A relates to B and B relates to C, infer indirect connections:
|
||||
```
|
||||
Sarah Chen works_at BetaStack
|
||||
BetaStack competes_with AlphaCloud
|
||||
→ Indirect: Sarah Chen is key_person_at competitor of AlphaCloud
|
||||
```
|
||||
|
||||
**Negation detection**: Watch for negated relationships that should NOT be added:
|
||||
```
|
||||
"Company X denied it was in acquisition talks with Company Y"
|
||||
→ Do NOT add acquired relation. Add entity note: "denied acquisition rumor, [date]"
|
||||
|
||||
"Former CEO of Company X" → Person left. Mark works_at as ended.
|
||||
```
|
||||
|
||||
### Temporal Event Extraction (Timeline Construction)
|
||||
|
||||
Extract dates and temporal markers to build event timelines.
|
||||
|
||||
**Explicit dates**:
|
||||
```
|
||||
"On March 15, 2025, Acme launched ProductX"
|
||||
→ event: product_launch, date: 2025-03-15, entities: [Acme, ProductX]
|
||||
```
|
||||
|
||||
**Relative dates** (resolve against article publication date):
|
||||
```
|
||||
"last week" → pub_date - 7 days
|
||||
"earlier today" → pub_date
|
||||
"next quarter" → pub_date + next fiscal quarter boundary
|
||||
"in Q3" → July-September of article's year
|
||||
"recently" → pub_date - 30 days (approximate, confidence: medium)
|
||||
```
|
||||
|
||||
**Temporal ordering heuristics**:
|
||||
```
|
||||
"before the acquisition" → event precedes known acquisition date
|
||||
"following the launch" → event follows known launch date
|
||||
"amid layoffs" → event concurrent with layoff period
|
||||
```
|
||||
|
||||
**Timeline output format**:
|
||||
```json
|
||||
{
|
||||
"entity": "Acme Corp",
|
||||
"timeline": [
|
||||
{"date": "2025-01-15", "event": "Series B ($40M)", "type": "funding", "confidence": "high"},
|
||||
{"date": "2025-03-20", "event": "Hired new CTO (Jane Lee)", "type": "leadership", "confidence": "high"},
|
||||
{"date": "2025-06-01", "event": "Launched v3.0", "type": "product", "confidence": "high"},
|
||||
{"date": "2025-08-10", "event": "Partnership with CloudCo", "type": "partnership", "confidence": "medium"},
|
||||
{"date": "2025-11-05", "event": "Acquired by BigCorp", "type": "acquisition", "confidence": "high"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Quantitative Data Extraction
|
||||
|
||||
Extract numerical data points with units, context, and time reference.
|
||||
|
||||
**Financial figures**:
|
||||
```
|
||||
Pattern: "[Company] raised $[amount][M/B] in [round]"
|
||||
Example: "Acme raised $40M in Series B"
|
||||
→ {metric: "funding", value: 40000000, currency: "USD", context: "Series B", entity: "Acme"}
|
||||
|
||||
Pattern: "[Company] revenue of $[amount][M/B]"
|
||||
Example: "reported annual revenue of $120M"
|
||||
→ {metric: "revenue", value: 120000000, currency: "USD", period: "annual", entity: subject}
|
||||
```
|
||||
|
||||
**Growth rates**:
|
||||
```
|
||||
Pattern: "[metric] grew [X]% [period]"
|
||||
Example: "ARR grew 45% year-over-year"
|
||||
→ {metric: "ARR_growth", value: 0.45, period: "YoY", entity: subject}
|
||||
|
||||
Pattern: "from [X] to [Y]"
|
||||
Example: "headcount grew from 200 to 350"
|
||||
→ {metric: "headcount", previous: 200, current: 350, growth: 0.75, entity: subject}
|
||||
```
|
||||
|
||||
**Headcounts and scale metrics**:
|
||||
```
|
||||
"[Company] now has [N] employees"
|
||||
"[Company] serves [N] customers"
|
||||
"[Product] has [N] monthly active users"
|
||||
"[Company] operates in [N] countries"
|
||||
```
|
||||
|
||||
**Extraction validation rules**:
|
||||
- Currency amounts without a clear entity reference: discard or mark confidence "low"
|
||||
- Growth percentages without a base period: mark confidence "medium"
|
||||
- Round numbers (e.g., "about 1,000 employees"): flag as approximate
|
||||
- Conflicting numbers from different sources: record both, note discrepancy
|
||||
|
||||
### Multi-Source Entity Resolution
|
||||
|
||||
When the same entity appears across different sources with variations, deduplicate.
|
||||
|
||||
**Company name normalization**:
|
||||
```
|
||||
"Acme Corp" = "Acme Corporation" = "Acme, Inc." = "ACME" (when context matches)
|
||||
"Google" = "Alphabet" (parent) — but keep as separate entities with parent_of relation
|
||||
```
|
||||
|
||||
**Resolution rules**:
|
||||
| Signal | Match Confidence | Action |
|
||||
|--------|-----------------|--------|
|
||||
| Exact name match | High | Merge immediately |
|
||||
| Name + same industry + same location | High | Merge |
|
||||
| Abbreviated name + same context | Medium | Merge with note |
|
||||
| Similar name, different industry | Low | Keep separate, flag for review |
|
||||
| Person same name, different company | Low | Keep separate unless linked by career event |
|
||||
|
||||
**Deduplication process**:
|
||||
1. Normalize: lowercase, strip legal suffixes, expand abbreviations
|
||||
2. Match: compare against existing entity list using normalized form
|
||||
3. Verify: check at least one corroborating attribute (industry, location, person association)
|
||||
4. Merge: combine attributes, keep all source references, use highest confidence level
|
||||
5. Log: record the merge decision for audit
|
||||
|
||||
```json
|
||||
{
|
||||
"canonical": "entity_acme_corp",
|
||||
"aliases": ["Acme Corp", "Acme Corporation", "Acme, Inc.", "ACME"],
|
||||
"merged_from": ["source_techcrunch_entity_12", "source_linkedin_entity_89"],
|
||||
"merge_confidence": "high",
|
||||
"merge_reason": "exact name + same industry (SaaS) + same HQ (San Francisco)"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Collection Automation Patterns
|
||||
|
||||
### Scheduled Collection Workflows
|
||||
|
||||
Define collection cadences matched to intelligence needs.
|
||||
|
||||
**Daily cycle** (for active competitive monitoring):
|
||||
```
|
||||
06:00 UTC — Run news queries for all targets (surface scan)
|
||||
06:15 UTC — Check social media and forums for overnight mentions
|
||||
06:30 UTC — Compare against yesterday's snapshot, flag changes
|
||||
06:45 UTC — Generate daily brief, send alerts for CRITICAL items
|
||||
```
|
||||
|
||||
**Weekly cycle** (for technology landscape and market mapping):
|
||||
```
|
||||
Monday — Full source sweep: news, blogs, official sites
|
||||
Tuesday — Job board scan: new postings, closed postings, pattern analysis
|
||||
Wednesday — Financial data: funding rounds, SEC filings, earnings
|
||||
Thursday — Community signals: GitHub activity, forum discussions, reviews
|
||||
Friday — Synthesis: generate weekly report, update entity graph, adjust queries
|
||||
```
|
||||
|
||||
**Event-triggered cycle** (supplement scheduled runs):
|
||||
```
|
||||
Trigger: CRITICAL change detected in any cycle
|
||||
→ Immediately run deep collection on the affected entity
|
||||
→ Expand query set to cover related entities
|
||||
→ Generate ad-hoc alert report
|
||||
→ Shorten next scheduled cycle interval (e.g., weekly → daily for 7 days)
|
||||
```
|
||||
|
||||
### Source Prioritization Based on Hit Rate
|
||||
|
||||
Track which sources consistently produce actionable intelligence and allocate collection effort accordingly.
|
||||
|
||||
**Hit rate calculation**:
|
||||
```
|
||||
hit_rate = (data_points_extracted / fetches_from_source) over last 10 cycles
|
||||
```
|
||||
|
||||
**Priority tiers**:
|
||||
| Hit Rate | Priority | Collection Behavior |
|
||||
|----------|----------|-------------------|
|
||||
| > 60% | Tier 1 | Always fetch, process first |
|
||||
| 30-60% | Tier 2 | Fetch on every cycle |
|
||||
| 10-30% | Tier 3 | Fetch every other cycle |
|
||||
| < 10% | Tier 4 | Fetch weekly regardless of cycle frequency |
|
||||
| 0% for 5+ cycles | Drop | Remove from active source list, log reason |
|
||||
|
||||
**Source performance tracking**:
|
||||
```json
|
||||
{
|
||||
"source": "techcrunch.com",
|
||||
"total_fetches": 48,
|
||||
"data_points_extracted": 31,
|
||||
"hit_rate": 0.65,
|
||||
"tier": 1,
|
||||
"avg_confidence": "medium-high",
|
||||
"last_hit": "2025-11-15",
|
||||
"best_queries": ["[company] funding", "[company] acquisition"]
|
||||
}
|
||||
```
|
||||
|
||||
### Incremental Collection (Only New/Changed Content)
|
||||
|
||||
Avoid re-processing unchanged content across cycles.
|
||||
|
||||
**Techniques**:
|
||||
1. **URL deduplication**: Maintain a set of already-processed URLs. Skip on subsequent cycles.
|
||||
2. **Content hashing**: Hash the extracted text body. If hash matches previous cycle, skip processing.
|
||||
3. **Date filtering**: Append date ranges to queries to limit results to new content.
|
||||
4. **Pagination cursors**: For APIs and structured sources, store the last-seen ID or timestamp.
|
||||
|
||||
**Query date narrowing**:
|
||||
```
|
||||
Cycle runs daily at 06:00 UTC:
|
||||
"AlphaCloud" after:2025-11-15 before:2025-11-16
|
||||
"AlphaCloud" news past 24 hours
|
||||
|
||||
Cycle runs weekly:
|
||||
"AlphaCloud" after:2025-11-08 before:2025-11-15
|
||||
```
|
||||
|
||||
**State tracking for incremental collection**:
|
||||
```json
|
||||
{
|
||||
"processed_urls": ["https://example.com/article-1", "..."],
|
||||
"content_hashes": {"url1": "sha256:abc123", "url2": "sha256:def456"},
|
||||
"last_collection_time": "2025-11-15T06:00:00Z",
|
||||
"query_cursors": {
|
||||
"techcrunch_rss": "2025-11-15T05:30:00Z",
|
||||
"github_api_events": "event_id_98765"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Alert Trigger Conditions and Escalation Rules
|
||||
|
||||
Define when and how to escalate detected changes.
|
||||
|
||||
**Trigger conditions**:
|
||||
```
|
||||
IMMEDIATE ALERT (publish event_publish within the cycle):
|
||||
- Leadership change at target company (CEO, CTO, CFO)
|
||||
- Acquisition or merger announcement
|
||||
- Funding round > $10M
|
||||
- Product discontinuation or major pivot
|
||||
- Regulatory action or legal filing
|
||||
- Data breach or security incident
|
||||
|
||||
DAILY DIGEST (batch into next daily report):
|
||||
- New product feature or version release
|
||||
- New partnership announcement
|
||||
- Hiring surge (> 5 new roles in a category)
|
||||
- Pricing or packaging change
|
||||
- Significant sentiment shift (score delta > 2 in one cycle)
|
||||
|
||||
WEEKLY SUMMARY (include in weekly report only):
|
||||
- Blog posts and thought leadership
|
||||
- Conference appearances
|
||||
- Minor version updates or patches
|
||||
- Individual job postings
|
||||
- Social media activity within normal range
|
||||
```
|
||||
|
||||
**Escalation rules**:
|
||||
```
|
||||
Level 1 — Auto-include in next scheduled report (default for all changes)
|
||||
Level 2 — event_publish immediately (for CRITICAL significance changes)
|
||||
Level 3 — event_publish + re-run deep collection on affected entity (for M&A, major crises)
|
||||
```
|
||||
|
||||
**False positive suppression**:
|
||||
- Require 2+ independent sources before triggering Level 2 alerts
|
||||
- Ignore "rumor" or "speculation" tagged content for immediate alerts
|
||||
- If the same alert fired in the previous cycle with no new corroboration, suppress repeat
|
||||
|
||||
---
|
||||
|
||||
## Analysis Techniques
|
||||
|
||||
### Link Analysis (Connection Mapping)
|
||||
|
||||
Map the network of relationships between entities to reveal hidden connections, influence patterns, and structural vulnerabilities.
|
||||
|
||||
**Building the adjacency map**:
|
||||
```
|
||||
From the knowledge graph, extract all relations and build:
|
||||
|
||||
Nodes: [Acme, BetaCo, GammaSuite, Jane Lee, CloudCo, InvestorX]
|
||||
Edges:
|
||||
Acme --competes_with--> BetaCo
|
||||
Acme --partnered_with--> CloudCo
|
||||
Jane Lee --works_at--> Acme
|
||||
Jane Lee --formerly--> BetaCo
|
||||
InvestorX --invested_in--> Acme
|
||||
InvestorX --invested_in--> GammaSuite
|
||||
```
|
||||
|
||||
**Key metrics to compute**:
|
||||
| Metric | Meaning | Use |
|
||||
|--------|---------|-----|
|
||||
| Degree centrality | Number of direct connections | Identifies most-connected entities |
|
||||
| Shared connections | Entities with overlapping relationships | Reveals indirect competition or collaboration |
|
||||
| Bridge nodes | Entities connecting otherwise separate clusters | Identifies key influencers or gatekeepers |
|
||||
| Cluster density | Ratio of actual to possible connections in a group | Measures how tightly coupled a set of entities is |
|
||||
|
||||
**Practical analysis patterns**:
|
||||
```
|
||||
Investor overlap:
|
||||
InvestorX invested_in Acme AND GammaSuite
|
||||
→ Potential: board-level information sharing, future merger pressure
|
||||
|
||||
Talent flow:
|
||||
Jane Lee: BetaCo (2020-2024) → Acme (2024-present)
|
||||
3 other engineers: BetaCo → Acme in same period
|
||||
→ Pattern: talent drain from BetaCo to Acme, possible IP risk
|
||||
|
||||
Supply chain dependency:
|
||||
Acme uses CloudCo infrastructure
|
||||
BetaCo uses CloudCo infrastructure
|
||||
→ Shared dependency: CloudCo outage affects both competitors
|
||||
```
|
||||
|
||||
### Timeline Analysis (Event Sequencing and Pattern Detection)
|
||||
|
||||
Arrange extracted events chronologically to detect causal chains, recurring patterns, and anomalous timing.
|
||||
|
||||
**Constructing the timeline**:
|
||||
```
|
||||
2025-01 Acme raises Series B ($40M)
|
||||
2025-02 Acme posts 15 engineering roles
|
||||
2025-03 Acme hires CTO from Google
|
||||
2025-05 Acme acquires small startup (data pipeline tool)
|
||||
2025-06 Acme launches v3.0 with data pipeline features
|
||||
2025-08 Acme announces enterprise pricing tier
|
||||
```
|
||||
|
||||
**Pattern detection rules**:
|
||||
|
||||
| Pattern | Sequence | Interpretation |
|
||||
|---------|----------|---------------|
|
||||
| Build-up to launch | Funding → Hiring surge → Leadership hire → Product release | Normal growth execution |
|
||||
| Acquisition integration | Acquire company → Quiet period (2-4 months) → Feature launch using acquired tech | Successful integration |
|
||||
| Pre-acquisition signals | Advisor hire → Leadership departures → Quiet period → Announcement | Target company being acquired |
|
||||
| Distress pattern | Layoffs → Pricing cuts → Leadership change → Pivot or shutdown | Company in trouble |
|
||||
| Expansion play | Funding → New market entry → Localized hiring → Regional partnerships | Geographic or vertical expansion |
|
||||
|
||||
**Anomaly detection**:
|
||||
```
|
||||
Expected: Funding round → hiring surge within 60 days
|
||||
Observed: Funding round → no hiring after 90 days
|
||||
→ Flag: "Post-funding hiring anomaly — possible pivot, internal issues, or stealth project"
|
||||
|
||||
Expected: Product launch → marketing push within 30 days
|
||||
Observed: Product launch → silence
|
||||
→ Flag: "Launch without marketing — possible soft launch, or product issues"
|
||||
```
|
||||
|
||||
### Trend Detection (Acceleration, Deceleration, Inflection Points)
|
||||
|
||||
Track metrics across collection cycles to identify directional shifts.
|
||||
|
||||
**Metric tracking format**:
|
||||
```json
|
||||
{
|
||||
"entity": "Acme Corp",
|
||||
"metric": "job_postings",
|
||||
"series": [
|
||||
{"cycle": 1, "date": "2025-09-01", "value": 12},
|
||||
{"cycle": 2, "date": "2025-09-08", "value": 18},
|
||||
{"cycle": 3, "date": "2025-09-15", "value": 31},
|
||||
{"cycle": 4, "date": "2025-09-22", "value": 45},
|
||||
{"cycle": 5, "date": "2025-09-29", "value": 42}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Trend classification**:
|
||||
| Pattern | Detection Rule | Meaning |
|
||||
|---------|---------------|---------|
|
||||
| Accelerating | Growth rate increasing cycle-over-cycle | Expanding investment in area |
|
||||
| Decelerating | Growth rate decreasing but still positive | Approaching saturation or shift in priorities |
|
||||
| Inflection point | Direction change (growth → decline or vice versa) | Strategic shift, market event, or external shock |
|
||||
| Plateau | Value stable within 10% for 3+ cycles | Steady state, maintenance mode |
|
||||
| Spike | Single-cycle jump > 2x previous value | One-time event (launch, announcement, crisis) |
|
||||
| Cliff | Single-cycle drop > 50% | Sudden change (layoff, shutdown, policy change) |
|
||||
|
||||
**Multi-metric correlation**:
|
||||
```
|
||||
When two metrics move together, the correlation strengthens the signal:
|
||||
|
||||
Acme job_postings: accelerating
|
||||
Acme github_commits: accelerating
|
||||
→ Corroborated signal: major development push underway
|
||||
|
||||
BetaCo job_postings: cliff (-60%)
|
||||
BetaCo glassdoor_rating: declining
|
||||
→ Corroborated signal: organizational distress
|
||||
```
|
||||
|
||||
### Competitive Positioning Maps
|
||||
|
||||
Synthesize collected intelligence into comparative frameworks.
|
||||
|
||||
**Feature parity matrix**:
|
||||
| Capability | Acme | BetaCo | GammaSuite | Your Product |
|
||||
|-----------|------|--------|------------|-------------|
|
||||
| Real-time dashboards | Yes (v2.0+) | Yes | Limited | Yes |
|
||||
| AI-powered alerts | Yes (new in v4.2) | No | Beta | Planned Q1 |
|
||||
| On-prem deployment | No | Yes | Yes | Yes |
|
||||
| SOC2 compliance | Yes | Yes | In progress | Yes |
|
||||
| Free tier | No | Yes (limited) | Yes | Yes |
|
||||
|
||||
**Market position quadrant** (based on collected metrics):
|
||||
```
|
||||
High Market Share
|
||||
|
|
||||
Leaders | Challengers
|
||||
(Acme) | (GammaSuite)
|
||||
|
|
||||
Low Growth ────────────┼──────────── High Growth
|
||||
|
|
||||
Declining | Emerging
|
||||
(Legacy Co) | (BetaCo)
|
||||
|
|
||||
Low Market Share
|
||||
```
|
||||
|
||||
Inputs for positioning:
|
||||
- **Market share proxy**: mention frequency, customer count, job posting volume
|
||||
- **Growth proxy**: funding recency, hiring rate, product release velocity, GitHub star velocity
|
||||
|
||||
**Pricing intelligence table**:
|
||||
| Tier | Acme | BetaCo | GammaSuite | Notes |
|
||||
|------|------|--------|------------|-------|
|
||||
| Free | -- | 5 users | 10 users | BetaCo most restrictive |
|
||||
| Team | $15/user/mo | $12/user/mo | $20/user/mo | BetaCo cheapest |
|
||||
| Enterprise | Custom | $35/user/mo | Custom | BetaCo only one with public enterprise pricing |
|
||||
| Notable changes | Raised Team tier 20% in Q3 | Unchanged 12 months | New tier added Q4 | Acme pricing pressure |
|
||||
|
||||
Track pricing changes across cycles — pricing increases signal confidence, decreases signal competitive pressure or churn concerns.
|
||||
@@ -490,6 +490,265 @@ token_consumption = "high"
|
||||
default_active = false
|
||||
activation_warning = "DevOps hand runs continuously and monitors infrastructure, consuming tokens."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "DevOps Hand"
|
||||
description = "自主 DevOps 工程师——CI/CD 管理、基础设施监控、部署自动化和事件响应"
|
||||
category = "开发"
|
||||
|
||||
[i18n.zh.settings.infrastructure]
|
||||
label = "基础设施类型"
|
||||
description = "主要基础设施平台"
|
||||
|
||||
[i18n.zh.settings.ci_platform]
|
||||
label = "CI/CD 平台"
|
||||
description = "主要 CI/CD 平台"
|
||||
|
||||
[i18n.zh.settings.monitoring_focus]
|
||||
label = "监控重点"
|
||||
description = "主要监控和告警的关注方向"
|
||||
|
||||
[i18n.zh.settings.auto_monitor]
|
||||
label = "自动监控"
|
||||
description = "自动监控基础设施并在出现问题时告警"
|
||||
|
||||
[i18n.zh.settings.check_interval]
|
||||
label = "健康检查间隔"
|
||||
description = "自动健康检查的执行频率"
|
||||
|
||||
[i18n.zh.settings.service_urls]
|
||||
label = "服务 URL"
|
||||
description = "要监控的 URL 列表,以逗号分隔(例如 https://api.example.com/health,https://app.example.com)"
|
||||
|
||||
[i18n.zh.settings.alert_on_failure]
|
||||
label = "故障告警"
|
||||
description = "健康检查失败时发布事件通知"
|
||||
|
||||
[i18n.zh.settings.rollback_strategy]
|
||||
label = "回滚策略"
|
||||
description = "部署失败时的默认回滚方式"
|
||||
|
||||
[i18n.zh.settings.approval_mode]
|
||||
label = "审批模式"
|
||||
description = "将部署和基础设施操作加入队列供审核,而非直接执行"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "DevOps Hand"
|
||||
description = "自律型DevOpsエンジニア——CI/CD管理、インフラ監視、デプロイ自動化、インシデント対応"
|
||||
category = "開発"
|
||||
|
||||
[i18n.ja.settings.infrastructure]
|
||||
label = "インフラタイプ"
|
||||
description = "主要なインフラプラットフォーム"
|
||||
|
||||
[i18n.ja.settings.ci_platform]
|
||||
label = "CI/CDプラットフォーム"
|
||||
description = "主要なCI/CDプラットフォーム"
|
||||
|
||||
[i18n.ja.settings.monitoring_focus]
|
||||
label = "監視の重点"
|
||||
description = "監視とアラートの主な対象分野"
|
||||
|
||||
[i18n.ja.settings.auto_monitor]
|
||||
label = "自動監視"
|
||||
description = "インフラを自動監視し、問題発生時にアラートを出す"
|
||||
|
||||
[i18n.ja.settings.check_interval]
|
||||
label = "ヘルスチェック間隔"
|
||||
description = "自動ヘルスチェックの実行間隔"
|
||||
|
||||
[i18n.ja.settings.service_urls]
|
||||
label = "サービスURL"
|
||||
description = "監視対象のURL一覧(カンマ区切り、例: https://api.example.com/health,https://app.example.com)"
|
||||
|
||||
[i18n.ja.settings.alert_on_failure]
|
||||
label = "障害アラート"
|
||||
description = "ヘルスチェック失敗時にイベント通知を発行する"
|
||||
|
||||
[i18n.ja.settings.rollback_strategy]
|
||||
label = "ロールバック戦略"
|
||||
description = "デプロイ失敗時のデフォルトのロールバック方法"
|
||||
|
||||
[i18n.ja.settings.approval_mode]
|
||||
label = "承認モード"
|
||||
description = "デプロイやインフラ操作を直接実行せず、レビュー用キューに追加する"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de DevOps"
|
||||
description = "Ingeniero DevOps autónomo — gestión de CI/CD, monitoreo de infraestructura, automatización de despliegues y respuesta a incidentes"
|
||||
category = "Desarrollo"
|
||||
|
||||
[i18n.es.settings.infrastructure]
|
||||
label = "Tipo de infraestructura"
|
||||
description = "Plataforma de infraestructura principal"
|
||||
|
||||
[i18n.es.settings.ci_platform]
|
||||
label = "Plataforma CI/CD"
|
||||
description = "Plataforma principal de CI/CD"
|
||||
|
||||
[i18n.es.settings.monitoring_focus]
|
||||
label = "Enfoque de monitoreo"
|
||||
description = "Área principal de monitoreo y alertas"
|
||||
|
||||
[i18n.es.settings.auto_monitor]
|
||||
label = "Monitoreo automático"
|
||||
description = "Monitorear automáticamente la infraestructura y alertar ante problemas"
|
||||
|
||||
[i18n.es.settings.check_interval]
|
||||
label = "Intervalo de comprobación de salud"
|
||||
description = "Con qué frecuencia ejecutar las comprobaciones de salud automatizadas"
|
||||
|
||||
[i18n.es.settings.service_urls]
|
||||
label = "URLs de servicios"
|
||||
description = "Lista de URLs a monitorear separadas por comas (ej. https://api.example.com/health,https://app.example.com)"
|
||||
|
||||
[i18n.es.settings.alert_on_failure]
|
||||
label = "Alertar ante fallos"
|
||||
description = "Publicar eventos cuando las comprobaciones de salud fallen"
|
||||
|
||||
[i18n.es.settings.rollback_strategy]
|
||||
label = "Estrategia de reversión"
|
||||
description = "Enfoque de reversión predeterminado para despliegues fallidos"
|
||||
|
||||
[i18n.es.settings.approval_mode]
|
||||
label = "Modo de aprobación"
|
||||
description = "Poner acciones de despliegue e infraestructura en cola para revisión en lugar de ejecutarlas directamente"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand DevOps"
|
||||
description = "Ingénieur DevOps autonome — gestion CI/CD, surveillance d'infrastructure, automatisation des déploiements et réponse aux incidents"
|
||||
category = "Développement"
|
||||
|
||||
[i18n.fr.settings.infrastructure]
|
||||
label = "Type d'infrastructure"
|
||||
description = "Plateforme d'infrastructure principale"
|
||||
|
||||
[i18n.fr.settings.ci_platform]
|
||||
label = "Plateforme CI/CD"
|
||||
description = "Plateforme CI/CD principale"
|
||||
|
||||
[i18n.fr.settings.monitoring_focus]
|
||||
label = "Axe de surveillance"
|
||||
description = "Domaine principal de surveillance et d'alerte"
|
||||
|
||||
[i18n.fr.settings.auto_monitor]
|
||||
label = "Surveillance automatique"
|
||||
description = "Surveiller automatiquement l'infrastructure et alerter en cas de problèmes"
|
||||
|
||||
[i18n.fr.settings.check_interval]
|
||||
label = "Intervalle de vérification de santé"
|
||||
description = "Fréquence d'exécution des vérifications de santé automatisées"
|
||||
|
||||
[i18n.fr.settings.service_urls]
|
||||
label = "URLs des services"
|
||||
description = "Liste d'URLs à surveiller séparées par des virgules (ex. https://api.example.com/health,https://app.example.com)"
|
||||
|
||||
[i18n.fr.settings.alert_on_failure]
|
||||
label = "Alerte en cas d'échec"
|
||||
description = "Publier des événements lorsque les vérifications de santé échouent"
|
||||
|
||||
[i18n.fr.settings.rollback_strategy]
|
||||
label = "Stratégie de retour en arrière"
|
||||
description = "Approche de retour en arrière par défaut pour les déploiements échoués"
|
||||
|
||||
[i18n.fr.settings.approval_mode]
|
||||
label = "Mode d'approbation"
|
||||
description = "Mettre les actions de déploiement et d'infrastructure en file d'attente pour révision au lieu de les exécuter directement"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "DevOps-Hand"
|
||||
description = "Autonomer DevOps-Ingenieur — CI/CD-Verwaltung, Infrastrukturüberwachung, Deployment-Automatisierung und Incident-Response"
|
||||
category = "Entwicklung"
|
||||
|
||||
[i18n.de.settings.infrastructure]
|
||||
label = "Infrastrukturtyp"
|
||||
description = "Primäre Infrastrukturplattform"
|
||||
|
||||
[i18n.de.settings.ci_platform]
|
||||
label = "CI/CD-Plattform"
|
||||
description = "Primäre CI/CD-Plattform"
|
||||
|
||||
[i18n.de.settings.monitoring_focus]
|
||||
label = "Überwachungsschwerpunkt"
|
||||
description = "Hauptbereich für Überwachung und Alarme"
|
||||
|
||||
[i18n.de.settings.auto_monitor]
|
||||
label = "Automatische Überwachung"
|
||||
description = "Infrastruktur automatisch überwachen und bei Problemen alarmieren"
|
||||
|
||||
[i18n.de.settings.check_interval]
|
||||
label = "Gesundheitscheck-Intervall"
|
||||
description = "Ausführungshäufigkeit der automatisierten Gesundheitschecks"
|
||||
|
||||
[i18n.de.settings.service_urls]
|
||||
label = "Service-URLs"
|
||||
description = "Kommagetrennte Liste der zu überwachenden URLs (z.B. https://api.example.com/health,https://app.example.com)"
|
||||
|
||||
[i18n.de.settings.alert_on_failure]
|
||||
label = "Warnung bei Ausfall"
|
||||
description = "Ereignisse veröffentlichen, wenn Gesundheitschecks fehlschlagen"
|
||||
|
||||
[i18n.de.settings.rollback_strategy]
|
||||
label = "Rollback-Strategie"
|
||||
description = "Standard-Rollback-Ansatz für fehlgeschlagene Deployments"
|
||||
|
||||
[i18n.de.settings.approval_mode]
|
||||
label = "Genehmigungsmodus"
|
||||
description = "Deployment- und Infrastrukturaktionen zur Überprüfung in die Warteschlange stellen, anstatt sie direkt auszuführen"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "DevOps Hand"
|
||||
description = "자율 DevOps 엔지니어 — CI/CD 관리, 인프라 모니터링, 배포 자동화 및 인시던트 대응"
|
||||
category = "개발"
|
||||
|
||||
[i18n.ko.settings.infrastructure]
|
||||
label = "인프라 유형"
|
||||
description = "주요 인프라 플랫폼"
|
||||
|
||||
[i18n.ko.settings.ci_platform]
|
||||
label = "CI/CD 플랫폼"
|
||||
description = "주요 CI/CD 플랫폼"
|
||||
|
||||
[i18n.ko.settings.monitoring_focus]
|
||||
label = "모니터링 중점"
|
||||
description = "주요 모니터링 및 알림 방향"
|
||||
|
||||
[i18n.ko.settings.auto_monitor]
|
||||
label = "자동 모니터링"
|
||||
description = "인프라를 자동으로 모니터링하고 문제 발생 시 알림"
|
||||
|
||||
[i18n.ko.settings.check_interval]
|
||||
label = "상태 점검 간격"
|
||||
description = "자동 상태 점검 실행 주기"
|
||||
|
||||
[i18n.ko.settings.service_urls]
|
||||
label = "서비스 URL"
|
||||
description = "모니터링할 URL 목록 (쉼표로 구분, 예: https://api.example.com/health,https://app.example.com)"
|
||||
|
||||
[i18n.ko.settings.alert_on_failure]
|
||||
label = "장애 알림"
|
||||
description = "상태 점검 실패 시 이벤트 알림 발행"
|
||||
|
||||
[i18n.ko.settings.rollback_strategy]
|
||||
label = "롤백 전략"
|
||||
description = "배포 실패 시 기본 롤백 방식"
|
||||
|
||||
[i18n.ko.settings.approval_mode]
|
||||
label = "승인 모드"
|
||||
description = "배포 및 인프라 작업을 직접 실행하지 않고 대기열에 추가하여 검토"
|
||||
@@ -330,3 +330,541 @@ for domain in api.example.com app.example.com; do
|
||||
echo "$domain: $expiry"
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Zero-Downtime Deployment Pipeline
|
||||
|
||||
Full lifecycle from code merge to production traffic switch with rollback safety.
|
||||
|
||||
**Phases**: CI build and push image -> deploy to Green -> health-gate -> traffic switch -> monitor -> done (or rollback).
|
||||
|
||||
**Traffic switch script** (the critical step):
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
# Record current slot for rollback, then switch
|
||||
CURRENT=$(kubectl get svc myapp-active -n production -o jsonpath='{.spec.selector.slot}')
|
||||
echo "$CURRENT" > /tmp/rollback-slot
|
||||
kubectl patch svc myapp-active -n production -p '{"spec":{"selector":{"slot":"green"}}}'
|
||||
# Verify
|
||||
sleep 5 && curl -sf https://api.example.com/api/health | jq '.version'
|
||||
```
|
||||
|
||||
**Rollback**: read `/tmp/rollback-slot`, patch the service selector back, verify health.
|
||||
|
||||
**Decision flowchart**:
|
||||
```
|
||||
Code merged to main
|
||||
|
|
||||
v
|
||||
CI build + test ----[FAIL]----> Block merge, notify author
|
||||
|
|
||||
[PASS]
|
||||
v
|
||||
Deploy to Green
|
||||
|
|
||||
v
|
||||
Health checks ------[FAIL]----> Alert on-call, keep Blue active
|
||||
|
|
||||
[PASS]
|
||||
v
|
||||
Switch traffic to Green
|
||||
|
|
||||
v
|
||||
Monitor 15 min -----[ERROR SPIKE]----> Rollback to Blue, open incident
|
||||
|
|
||||
[STABLE]
|
||||
v
|
||||
Mark Green as new Blue, done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Production Incident Response
|
||||
|
||||
Walkthrough of a real-world SEV1 incident: API latency spike caused by a database connection pool exhaustion.
|
||||
|
||||
**Timeline**
|
||||
|
||||
| Time (UTC) | Event | Actor |
|
||||
|------------|-------|-------|
|
||||
| 14:02 | PagerDuty alert: P95 latency > 2s on `/api/orders` | Monitoring |
|
||||
| 14:04 | On-call acknowledges, opens incident channel `#inc-2025-0312` | On-call engineer |
|
||||
| 14:06 | Check dashboard: request queue depth spiking, error rate at 12% | On-call engineer |
|
||||
| 14:10 | Identify DB connection pool at 100% utilization | On-call engineer |
|
||||
| 14:12 | Find long-running query from analytics job (started 13:55) | On-call engineer |
|
||||
| 14:14 | Kill the runaway query, pool starts draining | On-call engineer |
|
||||
| 14:18 | Latency returns to normal, error rate drops to 0.2% | Monitoring |
|
||||
| 14:20 | Incident mitigated, continue monitoring | On-call engineer |
|
||||
| 14:45 | Root cause confirmed: analytics cron job without query timeout | Investigation |
|
||||
| 15:00 | Incident resolved, post-mortem scheduled | Incident commander |
|
||||
|
||||
**Detection -- Alerting rules that fired**
|
||||
|
||||
```yaml
|
||||
# Prometheus alerting rule
|
||||
groups:
|
||||
- name: api-latency
|
||||
rules:
|
||||
- alert: HighAPILatency
|
||||
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{job="api"}[5m])) > 2
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "P95 latency above 2s for 2+ minutes"
|
||||
runbook: "https://wiki.internal/runbooks/high-latency"
|
||||
```
|
||||
|
||||
**Triage -- Quick diagnosis commands**
|
||||
|
||||
```bash
|
||||
# 1. Check if it's a specific endpoint or global
|
||||
curl -s "http://prometheus:9090/api/v1/query?query=topk(5,rate(http_request_duration_seconds_sum[5m])/rate(http_request_duration_seconds_count[5m]))" | jq '.data.result[] | {endpoint: .metric.handler, avg_latency: .value[1]}'
|
||||
|
||||
# 2. Check database connection pool
|
||||
psql -c "SELECT count(*) as total, state FROM pg_stat_activity GROUP BY state;"
|
||||
|
||||
# 3. Find the blocking query
|
||||
psql -c "SELECT pid, now() - query_start AS duration, query
|
||||
FROM pg_stat_activity
|
||||
WHERE state = 'active' AND now() - query_start > interval '1 minute'
|
||||
ORDER BY duration DESC LIMIT 5;"
|
||||
```
|
||||
|
||||
**Mitigation -- Kill the offending query**
|
||||
|
||||
```bash
|
||||
# Kill the long-running query by PID
|
||||
psql -c "SELECT pg_terminate_backend(12345);"
|
||||
|
||||
# Verify pool is recovering
|
||||
watch -n 2 'psql -t -c "SELECT count(*) FROM pg_stat_activity WHERE state = '\''active'\'';"'
|
||||
```
|
||||
|
||||
**Prevention -- Fix applied after incident**
|
||||
|
||||
```sql
|
||||
-- Set statement timeout for analytics role
|
||||
ALTER ROLE analytics_readonly SET statement_timeout = '300s';
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Add connection pool monitoring alert
|
||||
- alert: DBConnectionPoolNearCapacity
|
||||
expr: pg_stat_activity_count / pg_settings_max_connections > 0.8
|
||||
for: 1m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "DB connection pool above 80% capacity"
|
||||
```
|
||||
|
||||
**Post-mortem action items**:
|
||||
- [ ] Add `statement_timeout` to all non-interactive database roles
|
||||
- [ ] Add connection pool utilization alerts (threshold: 80%)
|
||||
- [ ] Move analytics queries to read replica
|
||||
- [ ] Add circuit breaker to API when pool utilization exceeds 90%
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Infrastructure Scaling Event
|
||||
|
||||
Scaling a Kubernetes deployment in response to sustained load increase.
|
||||
|
||||
**Phase 1 -- Alert triggers**
|
||||
|
||||
```
|
||||
Alert: HighCPUUtilization
|
||||
Condition: avg(cpu_usage) > 80% for 10 minutes
|
||||
Current: 87% across 3 pods
|
||||
Namespace: production
|
||||
Deployment: order-service
|
||||
```
|
||||
|
||||
**Phase 2 -- Capacity analysis**
|
||||
|
||||
```bash
|
||||
kubectl top pods -l app=order-service -n production # Per-pod CPU/memory
|
||||
kubectl describe nodes | grep -A 5 "Allocated resources" # Node headroom
|
||||
kubectl get hpa order-service -n production # Current HPA state
|
||||
# Result: 87% CPU across 3 pods, 842 req/s (2x baseline)
|
||||
```
|
||||
|
||||
**Phase 3 -- Scaling decision matrix**
|
||||
|
||||
| Metric | Current | Target | Action |
|
||||
|--------|---------|--------|--------|
|
||||
| CPU usage | 87% | < 70% | Scale out |
|
||||
| Request rate | 842/s | - | 2x normal, sustained |
|
||||
| Memory | 258Mi avg | 512Mi limit | Headroom OK |
|
||||
| Pod count | 3 | 6 (estimated) | Double replicas |
|
||||
| Node capacity | 72% | < 85% | Sufficient for 6 pods |
|
||||
|
||||
**Phase 4 -- Implement scaling**
|
||||
|
||||
```bash
|
||||
# Option A: Manual scale (immediate)
|
||||
kubectl scale deployment order-service -n production --replicas=6
|
||||
|
||||
# Option B: Adjust HPA for sustained load (preferred)
|
||||
kubectl patch hpa order-service -n production \
|
||||
-p '{"spec":{"minReplicas":5,"maxReplicas":15}}'
|
||||
|
||||
# Monitor rollout
|
||||
kubectl rollout status deployment/order-service -n production
|
||||
|
||||
# Watch pods come up
|
||||
kubectl get pods -l app=order-service -n production -w
|
||||
```
|
||||
|
||||
**Phase 5 -- Verify scaling**
|
||||
|
||||
Confirm via `kubectl top pods` (CPU should drop to ~45% per pod), check P95 latency is back below SLO, and verify error rate < 1%.
|
||||
|
||||
**Post-scaling actions**:
|
||||
- [ ] Investigate root cause of traffic increase (marketing event? bot traffic? organic growth?)
|
||||
- [ ] Update capacity planning spreadsheet
|
||||
- [ ] If sustained, adjust resource requests/limits and HPA baselines
|
||||
- [ ] Set calendar reminder to review and potentially scale down in 48h
|
||||
|
||||
---
|
||||
|
||||
## Observability Deep Dive
|
||||
|
||||
### Structured Logging
|
||||
|
||||
Use consistent JSON log format across all services for machine-parseable aggregation.
|
||||
|
||||
**Log format standard**: JSON with required fields: `timestamp`, `level`, `service`, `trace_id`, `span_id`, `request_id`, `message`. Add `error` and `context` (structured key-value) as needed.
|
||||
|
||||
**Log levels -- when to use each**:
|
||||
|
||||
| Level | Purpose | Example | Persisted |
|
||||
|-------|---------|---------|-----------|
|
||||
| `error` | Requires human attention | Payment processing failed | 90 days |
|
||||
| `warn` | Degraded but recoverable | Retry succeeded on 2nd attempt | 30 days |
|
||||
| `info` | Business-significant events | Order placed, user logged in | 14 days |
|
||||
| `debug` | Developer troubleshooting | Cache hit/miss, query timing | 3 days |
|
||||
| `trace` | Fine-grained flow tracking | Function entry/exit, variable state | 1 day (sampled) |
|
||||
|
||||
**Correlation IDs**: generate `X-Request-ID` at API gateway, propagate through all downstream calls. Query across services by filtering on `request_id.keyword` in Elasticsearch/OpenSearch.
|
||||
|
||||
### Distributed Tracing
|
||||
|
||||
**Core concepts**: A Trace is the end-to-end request path. Each service call is a Span with timing. Spans nest to show the call tree (e.g., API Gateway -> Order Service -> DB Query + Payment Service -> Stripe API).
|
||||
|
||||
**OpenTelemetry propagation**: `traceparent: 00-<trace-id>-<span-id>-<flags>`, `tracestate: vendor=value`.
|
||||
|
||||
**Useful trace queries (Jaeger/Tempo)**:
|
||||
```bash
|
||||
curl -s "http://jaeger:16686/api/traces?service=order-service&minDuration=1s&limit=20" # Slow traces
|
||||
curl -s "http://jaeger:16686/api/traces?service=order-service&tags=error%3Dtrue&limit=20" # Error traces
|
||||
```
|
||||
|
||||
### Alerting Best Practices
|
||||
|
||||
**Avoid alert fatigue -- rules of thumb**:
|
||||
- Every alert must have a runbook link
|
||||
- Every alert must be actionable (if no one needs to act, it is a log, not an alert)
|
||||
- Group related alerts to avoid notification storms
|
||||
- Use inhibition rules: if the cluster is down, suppress per-pod alerts
|
||||
|
||||
**SLO-based alerting (burn rate)**:
|
||||
```yaml
|
||||
# SLO: 99.9% availability = 43.2 min/month error budget
|
||||
# Fast burn (exhausts budget in 2h): error_ratio > 14.4 * 0.001 for 2m -> critical
|
||||
# Slow burn (exhausts budget in 3d): error_ratio > 3 * 0.001 for 15m -> warning
|
||||
groups:
|
||||
- name: slo-burn-rate
|
||||
rules:
|
||||
- alert: SLOBurnRateCritical
|
||||
expr: sum(rate(http_requests_total{code=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > (14.4 * 0.001)
|
||||
for: 2m
|
||||
labels: { severity: critical }
|
||||
- alert: SLOBurnRateWarning
|
||||
expr: sum(rate(http_requests_total{code=~"5.."}[1h])) / sum(rate(http_requests_total[1h])) > (3 * 0.001)
|
||||
for: 15m
|
||||
labels: { severity: warning }
|
||||
```
|
||||
|
||||
**Runbook template**: Each alert runbook should cover: what the alert means (one sentence), impact scope, diagnosis steps (dashboard + commands), mitigation (quick fix vs proper fix), and escalation path (who to contact after 15 min).
|
||||
|
||||
### Metrics Collection Patterns
|
||||
|
||||
**RED Method (request-scoped services)**:
|
||||
|
||||
| Metric | What | PromQL Example |
|
||||
|--------|------|----------------|
|
||||
| **R**ate | Requests per second | `sum(rate(http_requests_total[5m]))` |
|
||||
| **E**rrors | Failed requests per second | `sum(rate(http_requests_total{code=~"5.."}[5m]))` |
|
||||
| **D**uration | Latency distribution | `histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))` |
|
||||
|
||||
**USE Method (infrastructure resources)**:
|
||||
|
||||
| Metric | What | Example Check |
|
||||
|--------|------|---------------|
|
||||
| **U**tilization | % time resource is busy | `avg(rate(node_cpu_seconds_total{mode!="idle"}[5m]))` |
|
||||
| **S**aturation | Queue depth / backlog | `node_load1 / count(node_cpu_seconds_total{mode="idle"})` |
|
||||
| **E**rrors | Error event count | `rate(node_disk_io_time_weighted_seconds_total[5m])` |
|
||||
|
||||
**When to use which**:
|
||||
- RED for services that handle requests (APIs, web servers, message consumers)
|
||||
- USE for infrastructure (CPU, memory, disk, network interfaces, queues)
|
||||
- Combine both for a complete picture
|
||||
|
||||
---
|
||||
|
||||
## Security Operations
|
||||
|
||||
### Secret Management
|
||||
|
||||
**Principles**:
|
||||
- Never store secrets in source code, environment variables (in Dockerfiles), or container images
|
||||
- Use a secrets manager (Vault, AWS Secrets Manager, K8s Secrets with encryption at rest)
|
||||
- Rotate secrets on a schedule and immediately after any suspected compromise
|
||||
- Audit all secret access
|
||||
|
||||
**Vault pattern -- inject secrets at runtime**:
|
||||
```bash
|
||||
# Store a secret
|
||||
vault kv put secret/myapp/db \
|
||||
username="app_user" \
|
||||
password="$(openssl rand -base64 32)"
|
||||
|
||||
# Read a secret (application startup)
|
||||
vault kv get -format=json secret/myapp/db | jq -r '.data.data.password'
|
||||
|
||||
# Enable audit logging
|
||||
vault audit enable file file_path=/var/log/vault-audit.log
|
||||
```
|
||||
|
||||
**Kubernetes secrets -- from Vault using sidecar injector**:
|
||||
|
||||
Annotate the pod template with `vault.hashicorp.com/agent-inject: "true"`, specify the role and secret path. The Vault agent sidecar renders secrets to `/vault/secrets/` and the app sources them at startup. Key annotations: `agent-inject-secret-<name>` for the path, `agent-inject-template-<name>` for the rendering template.
|
||||
|
||||
**Secret rotation checklist**:
|
||||
- [ ] Generate new secret value
|
||||
- [ ] Update secret in secrets manager
|
||||
- [ ] Restart/reload affected services (rolling, not all-at-once)
|
||||
- [ ] Verify services authenticate with new secret
|
||||
- [ ] Revoke the old secret value
|
||||
- [ ] Confirm no services are still using the old secret
|
||||
|
||||
### Container Security Scanning
|
||||
|
||||
```bash
|
||||
# Scan image for vulnerabilities (Trivy) -- fail CI on critical
|
||||
trivy image --exit-code 1 --severity CRITICAL registry.example.com/myapp:$CI_COMMIT_SHA
|
||||
|
||||
# Scan K8s cluster for misconfigurations
|
||||
trivy k8s --report summary cluster
|
||||
```
|
||||
|
||||
**Dockerfile security essentials**: use pinned base image tags (not `:latest`), run as non-root (`USER app`), copy only needed files, never bake secrets into image layers.
|
||||
|
||||
### Network Security Policies
|
||||
|
||||
**Kubernetes NetworkPolicy -- default deny with explicit allow**:
|
||||
```yaml
|
||||
# Default deny all ingress, then allow specific paths
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-gateway-to-orders
|
||||
namespace: production
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels: { app: order-service }
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels: { app: api-gateway }
|
||||
ports:
|
||||
- { protocol: TCP, port: 8080 }
|
||||
```
|
||||
|
||||
Apply a `default-deny-ingress` policy (empty `podSelector`, `policyTypes: [Ingress]`) per namespace first, then layer allow rules on top.
|
||||
|
||||
### Compliance as Code
|
||||
|
||||
**Policy enforcement with OPA/Gatekeeper**: use `K8sRequiredResources` constraints to enforce `limits.cpu`, `limits.memory`, `requests.cpu`, `requests.memory` on all pods in production namespaces.
|
||||
|
||||
**Quick compliance audit commands**:
|
||||
```bash
|
||||
# Find pods without resource limits
|
||||
kubectl get pods -A -o json | jq -r '.items[] | select(.spec.containers[].resources.limits == null) | .metadata.namespace + "/" + .metadata.name'
|
||||
# Find containers running as root
|
||||
kubectl get pods -A -o json | jq -r '.items[] | select(.spec.containers[].securityContext.runAsNonRoot != true) | .metadata.namespace + "/" + .metadata.name'
|
||||
# Find ingress without TLS
|
||||
kubectl get ingress -A -o json | jq -r '.items[] | select(.spec.tls == null) | .metadata.namespace + "/" + .metadata.name'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Automation Patterns
|
||||
|
||||
### Auto-Remediation
|
||||
|
||||
**Restart on OOM (Kubernetes)**:
|
||||
```yaml
|
||||
# Built-in: set resource limits and let K8s handle OOM restarts
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: myapp
|
||||
resources:
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
# Liveness probe: restart if unhealthy
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
```
|
||||
|
||||
**Scale on load (HPA with custom metrics)**:
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: order-service
|
||||
spec:
|
||||
scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: order-service }
|
||||
minReplicas: 3
|
||||
maxReplicas: 20
|
||||
behavior:
|
||||
scaleUp: { stabilizationWindowSeconds: 60, policies: [{ type: Percent, value: 50, periodSeconds: 60 }] }
|
||||
scaleDown: { stabilizationWindowSeconds: 300, policies: [{ type: Percent, value: 25, periodSeconds: 120 }] }
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } }
|
||||
- type: Pods
|
||||
pods: { metric: { name: http_requests_per_second }, target: { type: AverageValue, averageValue: "1000" } }
|
||||
```
|
||||
|
||||
**Rotate secrets on expiry (CronJob)**:
|
||||
|
||||
Use a K8s CronJob (e.g., monthly `"0 2 1 * *"`) with a `secret-rotator` service account that: generates new password -> updates Vault -> alters DB role password -> triggers rolling restart via `kubectl rollout restart`.
|
||||
|
||||
### GitOps Workflow
|
||||
|
||||
**Repository as source of truth**:
|
||||
```
|
||||
infrastructure-repo/
|
||||
|-- apps/
|
||||
| |-- order-service/
|
||||
| | |-- deployment.yaml
|
||||
| | |-- service.yaml
|
||||
| | |-- hpa.yaml
|
||||
| | `-- kustomization.yaml
|
||||
| `-- payment-service/
|
||||
| |-- deployment.yaml
|
||||
| `-- kustomization.yaml
|
||||
|-- base/
|
||||
| |-- namespace.yaml
|
||||
| |-- network-policies.yaml
|
||||
| `-- resource-quotas.yaml
|
||||
`-- overlays/
|
||||
|-- staging/
|
||||
| `-- kustomization.yaml
|
||||
`-- production/
|
||||
`-- kustomization.yaml
|
||||
```
|
||||
|
||||
**Reconciliation loop (ArgoCD application)**:
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: order-service
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/org/infrastructure-repo.git
|
||||
targetRevision: main
|
||||
path: apps/order-service
|
||||
destination: { server: "https://kubernetes.default.svc", namespace: production }
|
||||
syncPolicy:
|
||||
automated: { prune: true, selfHeal: true }
|
||||
syncOptions: [CreateNamespace=true]
|
||||
retry: { limit: 3, backoff: { duration: 5s, factor: 2, maxDuration: 3m } }
|
||||
```
|
||||
|
||||
**GitOps deployment flow**:
|
||||
```
|
||||
Developer pushes image tag update to infrastructure-repo
|
||||
|
|
||||
v
|
||||
ArgoCD detects drift between git state and cluster state
|
||||
|
|
||||
v
|
||||
ArgoCD syncs: applies manifests from git to cluster
|
||||
|
|
||||
v
|
||||
Kubernetes rolls out new pods
|
||||
|
|
||||
v
|
||||
ArgoCD verifies health (readiness probes pass)
|
||||
|
|
||||
[HEALTHY] --> Done
|
||||
[DEGRADED] --> ArgoCD marks sync as failed, alerts on-call
|
||||
```
|
||||
|
||||
### Database Backup and Restore
|
||||
|
||||
**Automated backup (PostgreSQL)** -- run via cron `0 */6 * * *`:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
DB_NAME="production"
|
||||
BACKUP_DIR="/backups/postgres"
|
||||
|
||||
pg_dump -Fc -Z 9 "$DB_NAME" > "${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.dump"
|
||||
aws s3 cp "${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.dump" \
|
||||
"s3://backups-bucket/postgres/" --storage-class STANDARD_IA
|
||||
find "$BACKUP_DIR" -name "*.dump" -mtime +30 -delete
|
||||
```
|
||||
|
||||
**Restore procedure**:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
BACKUP_FILE=$1 # e.g., "production_20250315_060000.dump"
|
||||
RESTORE_DB="production_restore"
|
||||
|
||||
aws s3 cp "s3://backups-bucket/postgres/$BACKUP_FILE" /tmp/restore.dump
|
||||
psql -c "DROP DATABASE IF EXISTS $RESTORE_DB;" && psql -c "CREATE DATABASE $RESTORE_DB;"
|
||||
pg_restore -d "$RESTORE_DB" -j 4 --no-owner /tmp/restore.dump
|
||||
# Verify: check row counts on key tables, then clean up
|
||||
rm /tmp/restore.dump
|
||||
```
|
||||
|
||||
### Disaster Recovery Runbook Template
|
||||
|
||||
**Recovery Objectives**: Define RTO (e.g., 1 hour) and RPO (e.g., 6 hours) per service.
|
||||
|
||||
**Prerequisites**: backup storage access, Terraform state access, DNS management access, stakeholder comms channel.
|
||||
|
||||
| Scenario | Key Steps |
|
||||
|----------|-----------|
|
||||
| **Single service failure** | Check pod status -> restart deployment -> if fails, `kubectl rollout undo` -> verify health |
|
||||
| **Database failure** | `pg_isready` -> promote replica (or restore from backup) -> update connection strings -> verify data integrity |
|
||||
| **Full region outage** | Confirm via provider status page -> notify stakeholders -> switch DNS to DR region -> verify traffic -> failback when primary recovers |
|
||||
|
||||
**Communication template**: Subject `[INCIDENT] Service -- Status`. Body: what happened, impact, current status, ETA, next update time.
|
||||
|
||||
**Post-recovery checklist**: health checks passing, data integrity verified, monitoring restored, backups resumed, incident report filed, post-mortem scheduled within 48h.
|
||||
+476
-18
@@ -196,6 +196,67 @@ label = "Standard (+ company size, industry, tech stack)"
|
||||
value = "deep"
|
||||
label = "Deep (+ funding, recent news, social profiles)"
|
||||
|
||||
[[settings]]
|
||||
key = "lead_score_threshold"
|
||||
label = "Lead Score Threshold"
|
||||
description = "Minimum score (0-100) for a lead to be included in reports"
|
||||
setting_type = "select"
|
||||
default = "60"
|
||||
|
||||
[[settings.options]]
|
||||
value = "40"
|
||||
label = "40 — Include warm and hot leads"
|
||||
|
||||
[[settings.options]]
|
||||
value = "60"
|
||||
label = "60 — Warm leads and above (recommended)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "80"
|
||||
label = "80 — Hot leads only"
|
||||
|
||||
[[settings]]
|
||||
key = "qualification_framework"
|
||||
label = "Qualification Framework"
|
||||
description = "Sales qualification methodology to apply during lead scoring"
|
||||
setting_type = "select"
|
||||
default = "bant"
|
||||
|
||||
[[settings.options]]
|
||||
value = "bant"
|
||||
label = "BANT (Budget, Authority, Need, Timeline)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "meddic"
|
||||
label = "MEDDIC (Metrics, Economic Buyer, Decision Criteria, Process, Pain, Champion)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "auto"
|
||||
label = "Auto (BANT for SMB, MEDDIC for Enterprise)"
|
||||
|
||||
[[settings]]
|
||||
key = "crm_export_format"
|
||||
label = "CRM Export Format"
|
||||
description = "Generate an additional CRM-ready export alongside the standard report"
|
||||
setting_type = "select"
|
||||
default = "none"
|
||||
|
||||
[[settings.options]]
|
||||
value = "none"
|
||||
label = "None (standard report only)"
|
||||
|
||||
[[settings.options]]
|
||||
value = "hubspot"
|
||||
label = "HubSpot"
|
||||
|
||||
[[settings.options]]
|
||||
value = "salesforce"
|
||||
label = "Salesforce"
|
||||
|
||||
[[settings.options]]
|
||||
value = "pipedrive"
|
||||
label = "Pipedrive"
|
||||
|
||||
# ─── Agent configuration ─────────────────────────────────────────────────────
|
||||
|
||||
[agent]
|
||||
@@ -207,7 +268,7 @@ model = "default"
|
||||
max_tokens = 16384
|
||||
temperature = 0.3
|
||||
max_iterations = 50
|
||||
system_prompt = """You are Lead Hand — an autonomous lead generation engine that discovers, enriches, and delivers qualified leads 24/7.
|
||||
system_prompt = """You are Lead Hand — an autonomous lead generation engine that discovers, qualifies, enriches, and delivers sales-ready leads 24/7. You combine systematic web research with structured qualification frameworks (BANT/MEDDIC) to produce leads that sales teams can act on immediately.
|
||||
|
||||
## Phase 0 — Platform Detection (ALWAYS DO THIS FIRST)
|
||||
|
||||
@@ -225,7 +286,7 @@ Then set your approach:
|
||||
|
||||
On first run:
|
||||
1. Check memory_recall for `lead_hand_state` — if it exists, you're resuming
|
||||
2. Read the **User Configuration** section for target_industry, target_role, company_size, geo_focus, etc.
|
||||
2. Read the **User Configuration** section for target_industry, target_role, company_size, geo_focus, qualification_framework, lead_score_threshold, crm_export_format, etc.
|
||||
3. Create your delivery schedule using schedule_create based on `delivery_schedule` setting
|
||||
4. Load any existing lead database from `leads_database.json` via file_read (if it exists)
|
||||
|
||||
@@ -236,7 +297,7 @@ On subsequent runs:
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Target Profile Construction
|
||||
## Phase 2 — Ideal Customer Profile Construction & Refinement
|
||||
|
||||
Build an Ideal Customer Profile (ICP) from user settings:
|
||||
- Industry: from `target_industry` setting
|
||||
@@ -244,6 +305,13 @@ Build an Ideal Customer Profile (ICP) from user settings:
|
||||
- Company size filter: from `company_size` setting
|
||||
- Geography: from `geo_focus` setting
|
||||
|
||||
**ICP Refinement Loop** (run after every 3 reports):
|
||||
1. Analyze the top 20% of leads by score — what attributes do they share?
|
||||
2. Analyze the bottom 20% — what attributes caused low scores?
|
||||
3. Tighten ICP criteria based on patterns: narrow industry keywords, adjust company size range, add tech stack requirements
|
||||
4. Log ICP revisions to `icp_revision_log.json` with date and rationale
|
||||
5. memory_store `lead_hand_icp_version` with the current ICP revision number
|
||||
|
||||
Store the ICP in the knowledge graph:
|
||||
- knowledge_add_entity: ICP profile node
|
||||
- knowledge_add_relation: link ICP to target attributes
|
||||
@@ -263,22 +331,27 @@ Execute a multi-query web research loop:
|
||||
3. For promising results, use web_fetch to extract company/person details
|
||||
4. Extract structured lead data: name, title, company, company_url, linkedin_url (if public), email pattern
|
||||
|
||||
Target: discover 2-3x the `leads_per_report` setting to allow for filtering.
|
||||
Target: discover 2-3x the `leads_per_report` setting to allow for filtering and qualification.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Lead Enrichment
|
||||
|
||||
For each discovered lead, based on `enrichment_depth`:
|
||||
Apply enrichment based on `enrichment_depth` setting. Higher depth costs more tool calls but produces better-qualified leads.
|
||||
|
||||
**Basic**: name, title, company — already have this from discovery
|
||||
**Standard**: additionally fetch:
|
||||
**Basic**: name, title, company — already have this from discovery. Use for high-volume, low-touch lists.
|
||||
**Standard** (recommended default): additionally fetch:
|
||||
- Company website (web_fetch company_url) — extract: employee count, industry, tech stack, product description
|
||||
- Look for company on job boards — hiring signals indicate growth
|
||||
**Deep**: additionally fetch:
|
||||
- Cross-reference at least 2 sources per company to verify data accuracy
|
||||
**Deep** (best for enterprise targets): additionally fetch:
|
||||
- Recent funding news (web_search "[company] funding round")
|
||||
- Recent company news (web_search "[company] news 2025")
|
||||
- Social profiles (web_search "[person name] [company] linkedin twitter")
|
||||
- Competitive landscape (what tools/vendors they currently use)
|
||||
- Negative signals: layoffs, lawsuits, executive departures
|
||||
|
||||
**Enrichment depth escalation**: If a lead scores above 70 at Standard depth, automatically re-enrich at Deep depth to maximize qualification data. This targets deep enrichment resources only at the most promising leads.
|
||||
|
||||
Store enriched entities in knowledge graph:
|
||||
- knowledge_add_entity for each lead and company
|
||||
@@ -286,10 +359,44 @@ Store enriched entities in knowledge graph:
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Deduplication & Scoring
|
||||
## Phase 5 — Qualification
|
||||
|
||||
Apply the qualification framework configured by the `qualification_framework` setting.
|
||||
|
||||
### BANT Qualification (default — best for SMB/startup targets, short sales cycles)
|
||||
For each lead, assess four dimensions from enrichment data:
|
||||
- **Budget**: funding rounds, revenue estimates, pricing tier of current tools, job postings for related roles
|
||||
- **Authority**: is the contact a decision-maker? VP+, C-level, Director, listed on Leadership page
|
||||
- **Need**: job postings mentioning the pain point, tech stack gaps, competitor tool usage, forum complaints
|
||||
- **Timeline**: contract renewals, compliance deadlines, product launches, recent leadership changes
|
||||
|
||||
Apply BANT bonus points on top of the base score:
|
||||
Budget confirmed: +5 | Authority confirmed: +5 | Need confirmed: +5 | Timeline confirmed: +5 (max +20)
|
||||
|
||||
### MEDDIC Qualification (best for enterprise targets, $100K+ deal size)
|
||||
For each enterprise lead (500+ employees or score > 80), attempt to discover:
|
||||
- **Metrics**: quantifiable outcomes the buyer cares about (case studies, KPIs in job postings)
|
||||
- **Economic Buyer**: person with budget authority (CFO, CEO, VP Finance, Head of Procurement)
|
||||
- **Decision Criteria**: how they evaluate vendors (RFP docs, comparison posts, compliance requirements)
|
||||
- **Decision Process**: steps from evaluation to purchase (procurement team, legal review, pilot mentions)
|
||||
- **Identify Pain**: specific problems driving a purchase (support forums, reviews, analyst reports)
|
||||
- **Champion**: internal advocate (conference speakers, blog authors, open-source contributors)
|
||||
|
||||
Log the MEDDIC score as X/6 dimensions discovered per lead.
|
||||
|
||||
### Mixed-list strategy
|
||||
When the target list contains both SMB and enterprise leads:
|
||||
1. Run BANT on all leads (fast first pass)
|
||||
2. For enterprise leads that score A-grade (80+), run a MEDDIC deep pass
|
||||
3. Include the qualification framework used in the output for each lead
|
||||
|
||||
---
|
||||
|
||||
## Phase 6 — Deduplication & Scoring
|
||||
|
||||
1. Compare new leads against existing `leads_database.json`:
|
||||
- Match on: normalized company name + person name
|
||||
- Match on: company website domain (most stable identifier)
|
||||
- Skip exact duplicates
|
||||
- Update existing leads with new enrichment data
|
||||
2. Score each lead (0-100):
|
||||
@@ -298,40 +405,59 @@ Store enriched entities in knowledge graph:
|
||||
- Enrichment completeness: +20 (all fields populated)
|
||||
- Recency: +15 (company active recently)
|
||||
- Accessibility: +15 (public contact info available)
|
||||
3. Sort by score descending
|
||||
4. Take top N leads per `leads_per_report` setting
|
||||
Then apply qualification bonuses (BANT: up to +20, MEDDIC: up to +10 for 5+ dimensions)
|
||||
Then apply negative modifiers:
|
||||
- Recent layoffs (>10% headcount): -10
|
||||
- Lawsuit / regulatory action: -5
|
||||
- Executive turnover (CEO/CTO departed): -5
|
||||
3. Apply the `lead_score_threshold` — only include leads at or above this score
|
||||
4. Sort by score descending
|
||||
5. Take top N leads per `leads_per_report` setting
|
||||
6. If fewer leads meet the threshold than requested, report honestly: "Found X leads meeting quality threshold; Y additional leads are partial matches below threshold"
|
||||
|
||||
### Score interpretation for output:
|
||||
- 80-100 (A): Hot lead — prioritize immediate outreach
|
||||
- 60-79 (B): Warm lead — worth nurturing
|
||||
- 40-59 (C): Cool lead — needs further enrichment
|
||||
- 0-39 (D): Cold lead — deprioritize unless ICP changes
|
||||
|
||||
---
|
||||
|
||||
## Phase 6 — Report Generation
|
||||
## Phase 7 — Report Generation
|
||||
|
||||
Generate the report in the configured `output_format`:
|
||||
|
||||
**CSV format**:
|
||||
```csv
|
||||
Name,Title,Company,Company URL,Industry,Company Size,Score,Discovery Date,Notes
|
||||
Name,Title,Company,Company URL,Industry,Company Size,Score,Grade,Qualification,Discovery Date,Notes
|
||||
```
|
||||
|
||||
**JSON format**:
|
||||
```json
|
||||
[{"name": "...", "title": "...", "company": "...", "company_url": "...", "industry": "...", "size": "...", "score": 85, "discovered": "2025-01-15", "enrichment": {...}}]
|
||||
[{"name": "...", "title": "...", "company": "...", "company_url": "...", "industry": "...", "size": "...", "score": 85, "grade": "A", "qualification": {"framework": "BANT", "budget": true, "authority": true, "need": true, "timeline": false}, "discovered": "2025-01-15", "enrichment": {...}}]
|
||||
```
|
||||
|
||||
**Markdown Table format**:
|
||||
```markdown
|
||||
| # | Name | Title | Company | Score | Signal |
|
||||
|---|------|-------|---------|-------|--------|
|
||||
| # | Name | Title | Company | Score | Grade | Qualification | Key Signal |
|
||||
|---|------|-------|---------|-------|-------|---------------|------------|
|
||||
```
|
||||
|
||||
**CRM export** (when `crm_export_format` is set):
|
||||
- **hubspot**: JSON with HubSpot contact property names (firstname, lastname, jobtitle, company, hs_lead_status)
|
||||
- **salesforce**: CSV with Salesforce standard field names (FirstName, LastName, Title, Company, LeadSource, Rating)
|
||||
- **pipedrive**: JSON with Pipedrive person/organization fields (name, org_id, title, email)
|
||||
|
||||
Save report to: `lead_report_YYYY-MM-DD.{csv,json,md}`
|
||||
If CRM export is enabled, also save: `lead_report_YYYY-MM-DD_crm.{csv,json}`
|
||||
|
||||
---
|
||||
|
||||
## Phase 7 — State Persistence
|
||||
## Phase 8 — State Persistence
|
||||
|
||||
After each run:
|
||||
1. Update `leads_database.json` with all known leads (new + existing)
|
||||
2. memory_store `lead_hand_state` with: last_run, total_leads, report_count
|
||||
2. memory_store `lead_hand_state` with: last_run, total_leads, report_count, icp_version
|
||||
3. Update dashboard stats:
|
||||
- memory_store `lead_hand_leads_found` — total unique leads discovered
|
||||
- memory_store `lead_hand_reports_generated` — increment report count
|
||||
@@ -348,6 +474,7 @@ After each run:
|
||||
- If a search yields no results, try alternative queries before giving up
|
||||
- Always deduplicate before reporting — users hate seeing the same lead twice
|
||||
- Include your confidence level for enriched data (e.g. "email pattern: likely" vs "email: verified")
|
||||
- Quality over quantity: 10 well-qualified A-grade leads beat 50 unqualified names
|
||||
- If the user messages you directly, pause the pipeline and respond to their question
|
||||
"""
|
||||
|
||||
@@ -380,6 +507,337 @@ token_consumption = "medium"
|
||||
default_active = false
|
||||
activation_warning = "Lead hand runs continuously and generates leads on schedule, consuming tokens."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "线索生成 Hand"
|
||||
description = "自主线索生成——按计划发现、充实并交付合格的潜在客户"
|
||||
category = "数据"
|
||||
|
||||
[i18n.zh.settings.target_industry]
|
||||
label = "目标行业"
|
||||
description = "重点关注的行业垂直领域(例如 SaaS、金融科技、医疗健康、电子商务)"
|
||||
|
||||
[i18n.zh.settings.target_role]
|
||||
label = "目标职位"
|
||||
description = "要触达的决策者头衔(例如 CTO、工程副总裁、产品负责人)"
|
||||
|
||||
[i18n.zh.settings.company_size]
|
||||
label = "公司规模"
|
||||
description = "按公司规模筛选线索"
|
||||
|
||||
[i18n.zh.settings.lead_source]
|
||||
label = "线索来源"
|
||||
description = "发现线索的主要方式"
|
||||
|
||||
[i18n.zh.settings.output_format]
|
||||
label = "输出格式"
|
||||
description = "报告交付格式"
|
||||
|
||||
[i18n.zh.settings.leads_per_report]
|
||||
label = "每份报告线索数"
|
||||
description = "每份报告中包含的线索数量"
|
||||
|
||||
[i18n.zh.settings.delivery_schedule]
|
||||
label = "交付计划"
|
||||
description = "生成和交付线索报告的时间安排"
|
||||
|
||||
[i18n.zh.settings.geo_focus]
|
||||
label = "地域重点"
|
||||
description = "优先关注的地理区域(例如美国、欧洲、亚太、全球)"
|
||||
|
||||
[i18n.zh.settings.enrichment_depth]
|
||||
label = "信息丰富度"
|
||||
description = "对每条线索收集多少上下文信息"
|
||||
|
||||
[i18n.zh.settings.lead_score_threshold]
|
||||
label = "线索评分阈值"
|
||||
description = "报告中包含线索的最低评分(0-100)"
|
||||
|
||||
[i18n.zh.settings.qualification_framework]
|
||||
label = "资质评估框架"
|
||||
description = "线索评分时使用的销售资质评估方法论"
|
||||
|
||||
[i18n.zh.settings.crm_export_format]
|
||||
label = "CRM 导出格式"
|
||||
description = "在标准报告之外生成 CRM 可导入的文件"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "리드 생성 Hand"
|
||||
description = "자율 리드 생성 — 일정에 따라 적격 리드를 탐색, 보강 및 전달"
|
||||
category = "데이터"
|
||||
|
||||
[i18n.ko.settings.target_industry]
|
||||
label = "대상 산업"
|
||||
description = "집중할 산업 분야 (예: SaaS, 핀테크, 헬스케어, 이커머스)"
|
||||
|
||||
[i18n.ko.settings.target_role]
|
||||
label = "대상 직책"
|
||||
description = "타겟할 의사결정자 직함 (예: CTO, 엔지니어링 VP, 프로덕트 총괄)"
|
||||
|
||||
[i18n.ko.settings.company_size]
|
||||
label = "회사 규모"
|
||||
description = "회사 규모별 리드 필터링"
|
||||
|
||||
[i18n.ko.settings.lead_source]
|
||||
label = "리드 소스"
|
||||
description = "리드를 발굴하는 주요 방법"
|
||||
|
||||
[i18n.ko.settings.output_format]
|
||||
label = "출력 형식"
|
||||
description = "보고서 전달 형식"
|
||||
|
||||
[i18n.ko.settings.leads_per_report]
|
||||
label = "보고서당 리드 수"
|
||||
description = "각 보고서에 포함할 리드 수"
|
||||
|
||||
[i18n.ko.settings.delivery_schedule]
|
||||
label = "전달 일정"
|
||||
description = "리드 보고서 생성 및 전달 시간"
|
||||
|
||||
[i18n.ko.settings.geo_focus]
|
||||
label = "지역 중점"
|
||||
description = "우선적으로 집중할 지역 (예: 미국, 유럽, 아시아 태평양, 글로벌)"
|
||||
|
||||
[i18n.ko.settings.enrichment_depth]
|
||||
label = "보강 깊이"
|
||||
description = "리드당 수집할 컨텍스트 정보의 수준"
|
||||
|
||||
[i18n.ko.settings.lead_score_threshold]
|
||||
label = "리드 점수 기준"
|
||||
description = "보고서에 포함할 리드의 최소 점수 (0-100)"
|
||||
|
||||
[i18n.ko.settings.qualification_framework]
|
||||
label = "자격 평가 프레임워크"
|
||||
description = "리드 스코어링 시 적용할 영업 자격 평가 방법론"
|
||||
|
||||
[i18n.ko.settings.crm_export_format]
|
||||
label = "CRM 내보내기 형식"
|
||||
description = "표준 보고서와 함께 CRM 가져오기용 파일 생성"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "リード生成 Hand"
|
||||
description = "自律型リード生成エージェント——スケジュールに基づき見込み客を発見・情報付加・配信"
|
||||
category = "データ"
|
||||
|
||||
[i18n.ja.settings.target_industry]
|
||||
label = "ターゲット業界"
|
||||
description = "注力する業界バーティカル(例: SaaS、フィンテック、ヘルスケア、EC)"
|
||||
|
||||
[i18n.ja.settings.target_role]
|
||||
label = "ターゲット職種"
|
||||
description = "アプローチする意思決定者の肩書き(例: CTO、VP Engineering、プロダクト責任者)"
|
||||
|
||||
[i18n.ja.settings.company_size]
|
||||
label = "企業規模"
|
||||
description = "企業規模でリードをフィルタリング"
|
||||
|
||||
[i18n.ja.settings.lead_source]
|
||||
label = "リードソース"
|
||||
description = "リードを発見する主な方法"
|
||||
|
||||
[i18n.ja.settings.output_format]
|
||||
label = "出力形式"
|
||||
description = "レポートの配信形式"
|
||||
|
||||
[i18n.ja.settings.leads_per_report]
|
||||
label = "レポートあたりのリード数"
|
||||
description = "各レポートに含めるリードの数"
|
||||
|
||||
[i18n.ja.settings.delivery_schedule]
|
||||
label = "配信スケジュール"
|
||||
description = "リードレポートの生成・配信タイミング"
|
||||
|
||||
[i18n.ja.settings.geo_focus]
|
||||
label = "地域フォーカス"
|
||||
description = "優先する地理的リージョン(例: 米国、欧州、APAC、グローバル)"
|
||||
|
||||
[i18n.ja.settings.enrichment_depth]
|
||||
label = "情報付加の深さ"
|
||||
description = "リードごとに収集するコンテキスト情報の量"
|
||||
|
||||
[i18n.ja.settings.lead_score_threshold]
|
||||
label = "リードスコア閾値"
|
||||
description = "レポートに含めるリードの最低スコア(0-100)"
|
||||
|
||||
[i18n.ja.settings.qualification_framework]
|
||||
label = "資格評価フレームワーク"
|
||||
description = "リードスコアリング時に適用する営業資格評価の方法論"
|
||||
|
||||
[i18n.ja.settings.crm_export_format]
|
||||
label = "CRMエクスポート形式"
|
||||
description = "標準レポートに加えてCRMインポート用ファイルを生成"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Generación de Leads"
|
||||
description = "Generación autónoma de leads — descubre, enriquece y entrega leads cualificados según un calendario"
|
||||
category = "Datos"
|
||||
|
||||
[i18n.es.settings.target_industry]
|
||||
label = "Industria objetivo"
|
||||
description = "Vertical de industria en la que enfocarse (ej. SaaS, fintech, salud, e-commerce)"
|
||||
|
||||
[i18n.es.settings.target_role]
|
||||
label = "Rol objetivo"
|
||||
description = "Títulos de tomadores de decisiones a los que dirigirse (ej. CTO, VP de Ingeniería, Director de Producto)"
|
||||
|
||||
[i18n.es.settings.company_size]
|
||||
label = "Tamaño de empresa"
|
||||
description = "Filtrar leads por tamaño de empresa"
|
||||
|
||||
[i18n.es.settings.lead_source]
|
||||
label = "Fuente de leads"
|
||||
description = "Método principal para descubrir leads"
|
||||
|
||||
[i18n.es.settings.output_format]
|
||||
label = "Formato de salida"
|
||||
description = "Formato de entrega del informe"
|
||||
|
||||
[i18n.es.settings.leads_per_report]
|
||||
label = "Leads por informe"
|
||||
description = "Número de leads a incluir en cada informe"
|
||||
|
||||
[i18n.es.settings.delivery_schedule]
|
||||
label = "Calendario de entrega"
|
||||
description = "Cuándo generar y entregar los informes de leads"
|
||||
|
||||
[i18n.es.settings.geo_focus]
|
||||
label = "Enfoque geográfico"
|
||||
description = "Región geográfica a priorizar (ej. EE.UU., Europa, Asia-Pacífico, global)"
|
||||
|
||||
[i18n.es.settings.enrichment_depth]
|
||||
label = "Profundidad de enriquecimiento"
|
||||
description = "Cuánto contexto recopilar por cada lead"
|
||||
|
||||
[i18n.es.settings.lead_score_threshold]
|
||||
label = "Umbral de puntuación"
|
||||
description = "Puntuación mínima (0-100) para incluir un lead en los informes"
|
||||
|
||||
[i18n.es.settings.qualification_framework]
|
||||
label = "Marco de cualificación"
|
||||
description = "Metodología de cualificación comercial a aplicar durante la puntuación de leads"
|
||||
|
||||
[i18n.es.settings.crm_export_format]
|
||||
label = "Formato de exportación CRM"
|
||||
description = "Generar un archivo importable para CRM junto al informe estándar"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand Génération de Prospects"
|
||||
description = "Génération autonome de prospects — découvre, enrichit et livre des prospects qualifiés selon un calendrier"
|
||||
category = "Données"
|
||||
|
||||
[i18n.fr.settings.target_industry]
|
||||
label = "Secteur cible"
|
||||
description = "Secteur d'activité cible (ex. SaaS, fintech, santé, e-commerce)"
|
||||
|
||||
[i18n.fr.settings.target_role]
|
||||
label = "Poste cible"
|
||||
description = "Titres de décideurs à cibler (ex. CTO, VP Engineering, Directeur Produit)"
|
||||
|
||||
[i18n.fr.settings.company_size]
|
||||
label = "Taille d'entreprise"
|
||||
description = "Filtrer les prospects par taille d'entreprise"
|
||||
|
||||
[i18n.fr.settings.lead_source]
|
||||
label = "Source de prospects"
|
||||
description = "Méthode principale de découverte des prospects"
|
||||
|
||||
[i18n.fr.settings.output_format]
|
||||
label = "Format de sortie"
|
||||
description = "Format de livraison des rapports"
|
||||
|
||||
[i18n.fr.settings.leads_per_report]
|
||||
label = "Prospects par rapport"
|
||||
description = "Nombre de prospects à inclure dans chaque rapport"
|
||||
|
||||
[i18n.fr.settings.delivery_schedule]
|
||||
label = "Calendrier de livraison"
|
||||
description = "Quand générer et livrer les rapports de prospects"
|
||||
|
||||
[i18n.fr.settings.geo_focus]
|
||||
label = "Focus géographique"
|
||||
description = "Région géographique prioritaire (ex. USA, Europe, Asie-Pacifique, Mondial)"
|
||||
|
||||
[i18n.fr.settings.enrichment_depth]
|
||||
label = "Profondeur d'enrichissement"
|
||||
description = "Niveau d'informations contextuelles à collecter par prospect"
|
||||
|
||||
[i18n.fr.settings.lead_score_threshold]
|
||||
label = "Seuil de score"
|
||||
description = "Score minimum (0-100) pour inclure un prospect dans les rapports"
|
||||
|
||||
[i18n.fr.settings.qualification_framework]
|
||||
label = "Cadre de qualification"
|
||||
description = "Méthodologie de qualification commerciale appliquée lors du scoring des prospects"
|
||||
|
||||
[i18n.fr.settings.crm_export_format]
|
||||
label = "Format d'export CRM"
|
||||
description = "Générer un fichier importable CRM en plus du rapport standard"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Lead-Generierungs-Hand"
|
||||
description = "Autonome Lead-Generierung — entdeckt, bereichert und liefert qualifizierte Leads nach Zeitplan"
|
||||
category = "Daten"
|
||||
|
||||
[i18n.de.settings.target_industry]
|
||||
label = "Zielbranche"
|
||||
description = "Branchenvertikale für den Fokus (z.B. SaaS, Fintech, Gesundheitswesen, E-Commerce)"
|
||||
|
||||
[i18n.de.settings.target_role]
|
||||
label = "Zielposition"
|
||||
description = "Titel der Entscheidungsträger (z.B. CTO, VP Engineering, Produktleiter)"
|
||||
|
||||
[i18n.de.settings.company_size]
|
||||
label = "Unternehmensgröße"
|
||||
description = "Leads nach Unternehmensgröße filtern"
|
||||
|
||||
[i18n.de.settings.lead_source]
|
||||
label = "Lead-Quelle"
|
||||
description = "Primäre Methode zur Lead-Entdeckung"
|
||||
|
||||
[i18n.de.settings.output_format]
|
||||
label = "Ausgabeformat"
|
||||
description = "Berichtslieferformat"
|
||||
|
||||
[i18n.de.settings.leads_per_report]
|
||||
label = "Leads pro Bericht"
|
||||
description = "Anzahl der Leads pro Bericht"
|
||||
|
||||
[i18n.de.settings.delivery_schedule]
|
||||
label = "Lieferzeitplan"
|
||||
description = "Wann Lead-Berichte generiert und geliefert werden"
|
||||
|
||||
[i18n.de.settings.geo_focus]
|
||||
label = "Geografischer Fokus"
|
||||
description = "Priorisierte geografische Region (z.B. USA, Europa, Asien-Pazifik, Global)"
|
||||
|
||||
[i18n.de.settings.enrichment_depth]
|
||||
label = "Anreicherungstiefe"
|
||||
description = "Umfang der pro Lead gesammelten Kontextinformationen"
|
||||
|
||||
[i18n.de.settings.lead_score_threshold]
|
||||
label = "Lead-Score-Schwelle"
|
||||
description = "Mindestpunktzahl (0-100), um einen Lead in Berichte aufzunehmen"
|
||||
|
||||
[i18n.de.settings.qualification_framework]
|
||||
label = "Qualifizierungsrahmen"
|
||||
description = "Vertriebsqualifizierungsmethodik für die Lead-Bewertung"
|
||||
|
||||
[i18n.de.settings.crm_export_format]
|
||||
label = "CRM-Exportformat"
|
||||
description = "Zusätzlich zum Standardbericht eine CRM-importierbare Datei erstellen"
|
||||
+441
-4
@@ -25,6 +25,16 @@ A good ICP answers these questions:
|
||||
| SMB | 50-500 | $25K-$250K/yr | 1-3 months |
|
||||
| Enterprise | 500+ | $250K+/yr | 3-12 months |
|
||||
|
||||
### ICP Refinement Loop
|
||||
|
||||
The ICP should not be static. After every 3 report cycles, refine it:
|
||||
|
||||
1. **Analyze top performers**: Look at leads scored 80+ — what industry sub-segments, company sizes, and role patterns appear most often?
|
||||
2. **Analyze low performers**: Look at leads scored below 40 — which ICP criteria were they missing? Were there false positives from overly broad keywords?
|
||||
3. **Tighten criteria**: Narrow industry keywords (e.g., "fintech" becomes "payment infrastructure fintech"), adjust company size range, add or remove geographic regions, refine role titles.
|
||||
4. **Track revisions**: Log each ICP revision with date, changes made, and rationale. This creates an audit trail showing how targeting improved over time.
|
||||
5. **Measure impact**: Compare average lead score before and after each ICP revision. A well-refined ICP should produce higher average scores with fewer total leads — quality over quantity.
|
||||
|
||||
---
|
||||
|
||||
## Web Research Techniques for Lead Discovery
|
||||
@@ -62,6 +72,88 @@ site:builtwith.com "[company]"
|
||||
7. **News articles** — recent activity, reputation
|
||||
8. **Social media** — engagement, company culture
|
||||
|
||||
### Industry-Specific Search Patterns
|
||||
|
||||
#### SaaS / Technology
|
||||
```
|
||||
# Company directories
|
||||
site:g2.com/products "[category]"
|
||||
site:capterra.com "[category] software"
|
||||
site:producthunt.com "[product type]" "[year]"
|
||||
"[category] software" site:crunchbase.com/organization
|
||||
|
||||
# Tech stack signals
|
||||
site:stackshare.io "[technology]" decisions
|
||||
site:builtwith.com/websites/[technology]
|
||||
|
||||
# Growth signals
|
||||
"[company] SOC 2" OR "[company] ISO 27001" — enterprise readiness
|
||||
"[company] API" OR "[company] integration" — platform maturity
|
||||
"[company] case study" OR "[company] customer story" — traction evidence
|
||||
```
|
||||
|
||||
#### Healthcare
|
||||
```
|
||||
# Directories & registries
|
||||
site:healthcareittoday.com "[company]"
|
||||
"digital health companies" site:crunchbase.com
|
||||
"health tech" "[city/state]" site:angellist.co
|
||||
"HIPAA compliant" "[category] software"
|
||||
|
||||
# Regulatory signals
|
||||
"[company] FDA clearance" OR "[company] 510(k)"
|
||||
"[company] HIPAA" OR "[company] HITRUST"
|
||||
"[company] clinical trial" site:clinicaltrials.gov
|
||||
```
|
||||
|
||||
#### Financial Services
|
||||
```
|
||||
# Directories & databases
|
||||
site:fintechmagazine.com "top" "[category]"
|
||||
"fintech companies" "[region]" site:crunchbase.com
|
||||
"banking technology" OR "insurtech" site:cbinsights.com
|
||||
|
||||
# Compliance signals
|
||||
"[company] SOX compliance" OR "[company] PCI DSS"
|
||||
"[company] banking license" OR "[company] money transmitter"
|
||||
"[company] Series [A/B/C]" "fintech"
|
||||
```
|
||||
|
||||
#### E-commerce
|
||||
```
|
||||
# Directories & tools
|
||||
site:apps.shopify.com "[category]"
|
||||
site:store.bigcommerce.com "[category]"
|
||||
"ecommerce brands" "[niche]" site:2pm.com OR site:modernretail.co
|
||||
|
||||
# Revenue signals
|
||||
"[company] GMV" OR "[company] ARR"
|
||||
"[company] warehouse" OR "[company] fulfillment center"
|
||||
"[brand] DTC" OR "[brand] direct to consumer"
|
||||
```
|
||||
|
||||
#### Manufacturing
|
||||
```
|
||||
# Directories
|
||||
site:thomasnet.com "[product category]"
|
||||
"manufacturing companies" "[city/state]" site:mfg.com
|
||||
"industrial [category]" site:dnb.com
|
||||
|
||||
# Modernization signals
|
||||
"[company] Industry 4.0" OR "[company] smart factory"
|
||||
"[company] ERP" OR "[company] digital transformation"
|
||||
"[company] ISO 9001" OR "[company] ISO 14001"
|
||||
```
|
||||
|
||||
#### Industry Source Quick Reference
|
||||
| Vertical | Primary Directories | Key Signal Keywords |
|
||||
|----------|-------------------|---------------------|
|
||||
| SaaS/Tech | G2, Capterra, ProductHunt, Crunchbase | "API launch", "SOC 2", "Series X" |
|
||||
| Healthcare | HealthcareIT, ClinicalTrials.gov | "HIPAA", "FDA", "clinical trial" |
|
||||
| Financial Services | CBInsights, Crunchbase | "PCI DSS", "banking license", "Series X" |
|
||||
| E-commerce | Shopify App Store, ModernRetail | "GMV", "DTC", "fulfillment" |
|
||||
| Manufacturing | ThomasNet, MFG.com | "Industry 4.0", "ISO 9001", "ERP" |
|
||||
|
||||
---
|
||||
|
||||
## Lead Enrichment Patterns
|
||||
@@ -89,6 +181,17 @@ site:builtwith.com "[company]"
|
||||
- Company blog/content activity (engagement level)
|
||||
- Executive team changes
|
||||
|
||||
### Enrichment Depth Escalation Strategy
|
||||
|
||||
Not all leads deserve the same enrichment investment. Use a two-pass approach:
|
||||
|
||||
1. **First pass (Standard depth)**: Enrich all discovered leads at Standard depth. This is cost-effective and provides enough data for initial scoring.
|
||||
2. **Score checkpoint**: After the first pass, score all leads. Any lead scoring 70+ at Standard depth is a strong candidate.
|
||||
3. **Second pass (Deep depth)**: Re-enrich only leads scoring 70+ at Deep depth. This focuses expensive research (funding history, news, competitive analysis) on leads most likely to convert.
|
||||
4. **Skip threshold**: Leads scoring below 30 after Standard enrichment should not be enriched further — the data is unlikely to improve their score enough to matter.
|
||||
|
||||
This approach typically reduces total enrichment cost by 40-60% while maintaining the same output quality for top-tier leads.
|
||||
|
||||
### Email Pattern Discovery
|
||||
Common corporate email formats (try in order):
|
||||
1. `firstname@company.com` (most common for small companies)
|
||||
@@ -145,6 +248,66 @@ Accessibility (15 points max):
|
||||
|
||||
---
|
||||
|
||||
## Lead Qualification Frameworks
|
||||
|
||||
### BANT Framework
|
||||
|
||||
Use BANT to quickly qualify leads during or after enrichment. Each dimension maps to data you can discover through web research.
|
||||
|
||||
| Dimension | Question | Research Signals |
|
||||
|-----------|----------|-----------------|
|
||||
| **Budget** | Can they afford the solution? | Funding rounds, revenue estimates, job postings for related roles, pricing tier of current tools |
|
||||
| **Authority** | Is this person a decision-maker? | Title seniority (VP+, C-level, Director), reports to CEO/CTO, listed on "Leadership" page |
|
||||
| **Need** | Do they have the problem you solve? | Job postings mentioning the pain point, tech stack gaps, competitor tool usage, complaints on forums |
|
||||
| **Timeline** | Is there urgency to buy? | Contract renewals, compliance deadlines, product launches, recent leadership changes |
|
||||
|
||||
#### BANT Scoring Overlay
|
||||
Apply these modifiers on top of the base lead score:
|
||||
```
|
||||
Budget confirmed (funding, revenue signal): +5
|
||||
Authority confirmed (VP+ or C-level): +5
|
||||
Need confirmed (pain point evidence): +5
|
||||
Timeline confirmed (urgency signal): +5
|
||||
Max bonus: +20
|
||||
```
|
||||
|
||||
### MEDDIC Framework
|
||||
|
||||
Use MEDDIC for complex / enterprise sales qualification where longer deal cycles demand deeper research.
|
||||
|
||||
| Dimension | Definition | What to Look For |
|
||||
|-----------|-----------|-----------------|
|
||||
| **Metrics** | Quantifiable outcomes the buyer cares about | Case studies they publish, KPIs in job postings, analyst reports, earnings calls |
|
||||
| **Economic Buyer** | Person with budget authority to sign | CFO, CEO, VP Finance, or "Head of Procurement" listed on team pages |
|
||||
| **Decision Criteria** | Factors they use to evaluate vendors | RFP documents, vendor comparison blog posts, compliance requirements, review site feedback |
|
||||
| **Decision Process** | Steps from evaluation to purchase | Procurement team presence, legal/compliance review cycles, pilot program mentions |
|
||||
| **Identify Pain** | Specific problems driving the purchase | Support forums, Glassdoor reviews, social media complaints, analyst reports on industry challenges |
|
||||
| **Champion** | Internal advocate for your solution | Conference speakers, blog authors, open-source contributors, people who engage with your content |
|
||||
|
||||
#### MEDDIC Research Checklist
|
||||
```
|
||||
For each enterprise lead, attempt to discover:
|
||||
[ ] At least one quantifiable metric they care about
|
||||
[ ] The economic buyer's name and title
|
||||
[ ] 2+ decision criteria (compliance, performance, price, integration)
|
||||
[ ] Whether they run formal procurement (RFP, committee)
|
||||
[ ] 1+ specific pain point with evidence
|
||||
[ ] A potential internal champion (engaged user, tech advocate)
|
||||
```
|
||||
|
||||
### Choosing Between BANT and MEDDIC
|
||||
|
||||
The `qualification_framework` setting controls which framework is applied. When set to "auto", use this decision table:
|
||||
|
||||
| Scenario | Recommended Framework |
|
||||
|----------|----------------------|
|
||||
| SMB / startup targets, short sales cycle | BANT |
|
||||
| Enterprise targets, $100K+ deal size | MEDDIC |
|
||||
| Mixed list with varied company sizes | BANT first pass, MEDDIC for A-grade enterprise leads |
|
||||
| Time-constrained research | BANT (faster to assess) |
|
||||
|
||||
---
|
||||
|
||||
## Deduplication Strategies
|
||||
|
||||
### Matching Algorithm
|
||||
@@ -204,10 +367,206 @@ Name,Title,Company,Company URL,LinkedIn,Industry,Size,Score,Discovered,Notes
|
||||
|
||||
### Markdown Table Format
|
||||
```markdown
|
||||
| # | Name | Title | Company | Score | Key Signal |
|
||||
|---|------|-------|---------|-------|------------|
|
||||
| 1 | Jane Smith | VP Engineering | Acme Corp | 85 | Series B funded, hiring |
|
||||
| 2 | John Doe | CTO | Beta Inc | 72 | Product launch Q1 2025 |
|
||||
| # | Name | Title | Company | Score | Grade | Qualification | Key Signal |
|
||||
|---|------|-------|---------|-------|-------|---------------|------------|
|
||||
| 1 | Jane Smith | VP Engineering | Acme Corp | 85 | A | BANT 4/4 | Series B funded, hiring |
|
||||
| 2 | John Doe | CTO | Beta Inc | 72 | B | BANT 3/4 | Product launch Q1 2025 |
|
||||
```
|
||||
|
||||
### CRM Export Field Mappings
|
||||
|
||||
When `crm_export_format` is configured, produce an additional file with CRM-native field names:
|
||||
|
||||
**HubSpot** (JSON):
|
||||
| Lead Field | HubSpot Property |
|
||||
|------------|-----------------|
|
||||
| first_name | `firstname` |
|
||||
| last_name | `lastname` |
|
||||
| title | `jobtitle` |
|
||||
| company | `company` |
|
||||
| company_url | `website` |
|
||||
| industry | `industry` |
|
||||
| score | `hs_lead_status` (mapped: 80+ = "New", 60-79 = "Open", <60 = "In Progress") |
|
||||
|
||||
**Salesforce** (CSV):
|
||||
| Lead Field | Salesforce Field |
|
||||
|------------|-----------------|
|
||||
| first_name | `FirstName` |
|
||||
| last_name | `LastName` |
|
||||
| title | `Title` |
|
||||
| company | `Company` |
|
||||
| company_url | `Website` |
|
||||
| industry | `Industry` |
|
||||
| score | `Rating` (mapped: 80+ = "Hot", 60-79 = "Warm", <60 = "Cold") |
|
||||
| lead_source | `LeadSource` |
|
||||
|
||||
**Pipedrive** (JSON):
|
||||
| Lead Field | Pipedrive Field |
|
||||
|------------|----------------|
|
||||
| full_name | `name` |
|
||||
| title | `job_title` |
|
||||
| company | `org_name` |
|
||||
| company_url | `org_address` |
|
||||
| notes | `note` |
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Fintech SaaS Series A/B Companies (50-200 Employees)
|
||||
|
||||
**Objective**: Find 10 SaaS companies in the fintech space with 50-200 employees that recently raised Series A or B.
|
||||
|
||||
#### Step 1 — Define ICP
|
||||
```
|
||||
Industry: Fintech / Financial Technology
|
||||
Company size: 50-200 employees (SMB)
|
||||
Funding stage: Series A or Series B (raised within last 18 months)
|
||||
Geography: United States (primary), UK/EU (secondary)
|
||||
Decision-maker: VP Engineering, CTO, or Head of Product
|
||||
Pain points: Scaling infrastructure, compliance automation, developer tooling
|
||||
```
|
||||
|
||||
#### Step 2 — Execute Search Queries
|
||||
```
|
||||
# Primary discovery queries
|
||||
"fintech" "series A" OR "series B" site:crunchbase.com/organization
|
||||
"fintech startup" "raised" "$" "2025" OR "2024" site:techcrunch.com
|
||||
site:news.crunchbase.com "fintech" "series A" OR "series B"
|
||||
|
||||
# Employee count validation
|
||||
"fintech" "50" OR "100" OR "150" "employees" site:linkedin.com/company
|
||||
site:builtin.com/companies/fintech "51-200 employees"
|
||||
|
||||
# Growth signals
|
||||
"fintech" hiring "senior engineer" OR "staff engineer" site:linkedin.com/jobs
|
||||
"fintech startup" "SOC 2" OR "PCI DSS" — compliance-ready = selling to banks
|
||||
```
|
||||
|
||||
#### Step 3 — Enrich and Score Each Lead
|
||||
```
|
||||
For each discovered company, gather:
|
||||
1. Company website → About page → leadership team, employee count
|
||||
2. Crunchbase profile → funding amount, date, investors, total raised
|
||||
3. LinkedIn company page → exact employee count, recent hires
|
||||
4. Job boards → open roles (signals growth and tech stack)
|
||||
5. Press releases → product launches, partnerships, customer wins
|
||||
|
||||
Scoring example for "PayFlow Inc":
|
||||
ICP Match: 25/30 (fintech ✓, 130 employees ✓, US ✓, CTO found ✓, no geography bonus)
|
||||
Growth Signals: 18/20 (Series B $18M ✓, hiring 8 engineers ✓, product launch ✓)
|
||||
Enrichment: 15/20 (LinkedIn ✓, full company data ✓, tech stack ✓, no direct email)
|
||||
Recency: 15/15 (funding announced 3 weeks ago)
|
||||
Accessibility: 10/15 (company contact form, CTO LinkedIn)
|
||||
TOTAL: 83/100 → Grade A
|
||||
```
|
||||
|
||||
#### Step 4 — Final Output (top 3 of 10)
|
||||
| # | Name | Title | Company | Employees | Funding | Score | Key Signal |
|
||||
|---|------|-------|---------|-----------|---------|-------|------------|
|
||||
| 1 | Sarah Chen | CTO | PayFlow Inc | 130 | Series B, $18M | 83 | Funded 3 weeks ago, hiring 8 engineers |
|
||||
| 2 | Marcus Rivera | VP Engineering | LendStack | 85 | Series A, $12M | 78 | Launched API platform Q4, SOC 2 certified |
|
||||
| 3 | Priya Patel | Head of Product | ComplianceAI | 62 | Series A, $8M | 75 | Hiring product + eng, regulatory focus |
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Enterprise AI/ML Decision-Makers
|
||||
|
||||
**Objective**: Identify decision-makers at enterprise companies (500+ employees) that are actively adopting AI/ML tools.
|
||||
|
||||
#### Step 1 — Define ICP
|
||||
```
|
||||
Industry: Any (cross-industry AI adoption)
|
||||
Company size: 500+ employees (Enterprise)
|
||||
Signals: Active AI/ML adoption (hiring, projects, tool procurement)
|
||||
Geography: North America
|
||||
Decision-maker: VP/Director of Data Science, Head of AI/ML, CTO, Chief Data Officer
|
||||
Pain points: ML model deployment, data pipeline scaling, AI governance
|
||||
```
|
||||
|
||||
#### Step 2 — Execute Search Queries
|
||||
```
|
||||
# Identify companies investing in AI
|
||||
"head of AI" OR "VP data science" OR "chief data officer" hiring site:linkedin.com
|
||||
"[company] machine learning" "team" OR "department" site:linkedin.com/company
|
||||
"AI adoption" OR "ML platform" "enterprise" site:venturebeat.com OR site:techcrunch.com
|
||||
|
||||
# Conference and community signals
|
||||
"speaker" "machine learning" OR "AI" site:neurips.cc OR site:icml.cc
|
||||
"[company] MLOps" OR "[company] AI infrastructure" site:github.com
|
||||
|
||||
# Budget and procurement signals
|
||||
"AI budget" OR "ML tools" RFP site:gov OR site:rfpdb.com
|
||||
"[company] partnership" "AI" OR "machine learning" press release
|
||||
```
|
||||
|
||||
#### Step 3 — Multi-Source Enrichment
|
||||
```
|
||||
For enterprise targets, cross-reference at least 3 sources per lead:
|
||||
|
||||
Source 1: LinkedIn
|
||||
→ Title confirmation, tenure, reporting structure
|
||||
→ Company employee count, growth rate
|
||||
→ Recent posts about AI/ML topics (champion signal)
|
||||
|
||||
Source 2: Company website + press
|
||||
→ AI/ML team page, published case studies
|
||||
→ Press releases about AI initiatives
|
||||
→ Open positions on careers page
|
||||
|
||||
Source 3: Community / conferences
|
||||
→ Conference talks (NeurIPS, ICML, KDD, MLOps World)
|
||||
→ GitHub contributions (open-source ML projects)
|
||||
→ Blog posts or whitepapers on AI strategy
|
||||
|
||||
MEDDIC qualification pass:
|
||||
Metrics: "Reduced model deployment time by 60%" (from case study)
|
||||
Economic Buyer: Chief Data Officer, reports to CEO
|
||||
Decision Criteria: SOC 2 compliance, on-prem option, Python SDK
|
||||
Decision Process: Procurement committee, 90-day eval period
|
||||
Pain: "Manual ML pipeline taking 3 weeks per model" (job posting)
|
||||
Champion: Sr. ML Engineer who spoke at MLOps World about tooling gaps
|
||||
```
|
||||
|
||||
#### Step 4 — Final Output (top 3)
|
||||
| # | Name | Title | Company | Employees | Score | Qualification |
|
||||
|---|------|-------|---------|-----------|-------|---------------|
|
||||
| 1 | David Kim | Chief Data Officer | GlobalRetail Corp | 3,200 | 91 | MEDDIC 5/6: metrics, buyer, criteria, pain, champion |
|
||||
| 2 | Lisa Zhang | VP Data Science | HealthFirst Systems | 1,800 | 86 | MEDDIC 4/6: buyer, criteria, pain, champion |
|
||||
| 3 | James O'Brien | Director of AI | MegaBank Financial | 12,000 | 80 | MEDDIC 4/6: metrics, buyer, decision process, pain |
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Quick-Turn SMB List Build
|
||||
|
||||
**Objective**: Build a 20-lead list of SMB e-commerce brands using Shopify that might need an email marketing tool. Time budget: 30 minutes.
|
||||
|
||||
#### Abbreviated Flow
|
||||
```
|
||||
ICP (quick):
|
||||
Industry: E-commerce / DTC brands
|
||||
Size: 10-100 employees
|
||||
Platform: Shopify
|
||||
Signal: Active store, social media presence, no advanced email tool detected
|
||||
|
||||
Search queries (5 minutes):
|
||||
site:myshopify.com "[niche]"
|
||||
"[niche] brand" "shopify" site:linkedin.com/company
|
||||
site:apps.shopify.com/reviews "[competitor email tool]" — negative reviews = opportunity
|
||||
"DTC brands" "[niche]" "founded 2022" OR "founded 2023"
|
||||
|
||||
Enrichment (15 minutes, per lead):
|
||||
1. Shopify store URL → active? recent products?
|
||||
2. LinkedIn company page → employee count, founded year
|
||||
3. BuiltWith → check for existing email/marketing tools
|
||||
4. Instagram/TikTok → follower count (engagement proxy)
|
||||
|
||||
Scoring (5 minutes):
|
||||
Use simplified scoring: ICP match (40%) + Growth signals (30%) + Reachability (30%)
|
||||
Skip MEDDIC for SMB — use BANT quick-check instead
|
||||
|
||||
Output (5 minutes):
|
||||
Deliver as CSV with columns: Brand, URL, Employees, Platform, Current Email Tool, Score, Contact
|
||||
```
|
||||
|
||||
---
|
||||
@@ -233,3 +592,81 @@ Name,Title,Company,Company URL,LinkedIn,Industry,Size,Score,Discovered,Notes
|
||||
- Keep lead data in local files only — never exfiltrate
|
||||
- Mark stale leads (>90 days without activity) for review
|
||||
- Provide clear data export in all supported formats
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### 1. Outdated Data
|
||||
**Problem**: Company details change fast — people change jobs, startups pivot, funding info ages.
|
||||
**Mitigation**:
|
||||
- Verify every lead against at least 2 sources, and prefer sources updated within the last 90 days
|
||||
- Flag any data point older than 6 months as "needs re-verification"
|
||||
- Check LinkedIn tenure: if a contact joined their current role <3 months ago, they may not have budget authority yet
|
||||
|
||||
### 2. Over-Relying on a Single Source
|
||||
**Problem**: Crunchbase has gaps in non-US companies. LinkedIn employee counts lag. News articles are biased toward funded companies.
|
||||
**Mitigation**:
|
||||
- Always cross-reference: Crunchbase funding + LinkedIn headcount + company website team page
|
||||
- Use at least 2 sources for employee count (the numbers often diverge by 20-30%)
|
||||
- If a company has zero press coverage, check industry-specific directories rather than discarding it
|
||||
|
||||
### 3. Ignoring Enrichment Quality
|
||||
**Problem**: A lead list with 50 names but only 10 have titles and 5 have company size data is not actionable.
|
||||
**Mitigation**:
|
||||
- Set a minimum enrichment threshold before including a lead (e.g., must have: name + title + company + at least one signal)
|
||||
- Track an "enrichment completeness" percentage per lead
|
||||
- Return to partially-enriched leads in a second pass rather than shipping incomplete data
|
||||
|
||||
### 4. Vanity List Sizes
|
||||
**Problem**: Delivering 100 leads when only 15 are qualified wastes the user's time and erodes trust.
|
||||
**Mitigation**:
|
||||
- Better to deliver 10 A-grade leads than 50 C-grade leads
|
||||
- Always sort by score descending and include a clear recommendation on where to draw the cut-off line
|
||||
- If the target count cannot be met at acceptable quality, say so: "Found 7 leads meeting all criteria; 13 additional leads are partial matches"
|
||||
|
||||
### 5. Confusing Company Name Variants
|
||||
**Problem**: "Stripe, Inc.", "Stripe", and "Stripe Payments Europe Ltd" can appear as three separate leads.
|
||||
**Mitigation**:
|
||||
- Always normalize company names before deduplication (see Normalization Rules above)
|
||||
- Match on website domain as the primary key — it is the most stable identifier
|
||||
- Be especially careful with common words as company names ("Bolt", "Block", "Square")
|
||||
|
||||
### 6. Mistaking Hiring Activity for Purchase Intent
|
||||
**Problem**: A company hiring engineers does not necessarily mean they are buying your product.
|
||||
**Mitigation**:
|
||||
- Hiring is a **growth signal**, not a **purchase signal** — score it accordingly (contributor, not decisive)
|
||||
- Look for more direct signals: RFPs, vendor comparison blog posts, demo requests, event attendance
|
||||
- Combine hiring data with tech stack analysis: hiring a "Salesforce Admin" means Salesforce budget exists
|
||||
|
||||
### 7. Neglecting Negative Signals
|
||||
**Problem**: Focusing only on positive signals and missing red flags.
|
||||
**Mitigation**:
|
||||
- Check for layoffs, lawsuits, or executive departures — these reduce lead quality
|
||||
- A company that just went through a 30% layoff is unlikely to approve new vendor spend
|
||||
- Apply negative score modifiers:
|
||||
```
|
||||
Recent layoffs (>10% headcount): -10
|
||||
Lawsuit / regulatory action: -5
|
||||
Executive turnover (CEO/CTO left): -5
|
||||
Declining web traffic (per SimilarWeb): -3
|
||||
```
|
||||
|
||||
### 8. Skipping the ICP Step
|
||||
**Problem**: Jumping straight into search without a clear ICP produces scattered, low-quality results.
|
||||
**Mitigation**:
|
||||
- Always define the ICP **before** the first search query, even if it takes 5 extra minutes
|
||||
- Write the ICP down explicitly (industry, size, geography, role, pain point, budget signal)
|
||||
- Revisit and tighten the ICP after the first 10 leads if results are too broad
|
||||
|
||||
### Pitfall Severity Quick Reference
|
||||
| Pitfall | Severity | Frequency | Fix Effort |
|
||||
|---------|----------|-----------|------------|
|
||||
| Outdated data | High | Very common | Medium (multi-source verification) |
|
||||
| Single source reliance | High | Common | Low (add 1-2 extra sources) |
|
||||
| Poor enrichment quality | Medium | Common | Medium (set thresholds, second pass) |
|
||||
| Vanity list sizes | Medium | Common | Low (enforce scoring cut-off) |
|
||||
| Company name variants | Medium | Very common | Low (normalize + domain match) |
|
||||
| Hiring != purchase intent | Low | Occasional | Low (adjust scoring weight) |
|
||||
| Ignoring negative signals | High | Common | Medium (add negative modifiers) |
|
||||
| Skipping ICP | High | Occasional | Low (5-minute discipline) |
|
||||
@@ -394,6 +394,241 @@ frequency = "daily"
|
||||
token_consumption = "medium"
|
||||
default_active = false
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "LinkedIn Hand"
|
||||
description = "自主 LinkedIn 管理——个人资料优化、内容创作、人脉拓展和职业互动"
|
||||
category = "通信"
|
||||
|
||||
[i18n.zh.settings.content_style]
|
||||
label = "内容风格"
|
||||
description = "LinkedIn 帖子的语气和风格"
|
||||
|
||||
[i18n.zh.settings.post_frequency]
|
||||
label = "发布频率"
|
||||
description = "创建和发布内容的频率"
|
||||
|
||||
[i18n.zh.settings.content_topics]
|
||||
label = "内容主题"
|
||||
description = "要创作内容的主题(逗号分隔,例如 AI、领导力、创业)"
|
||||
|
||||
[i18n.zh.settings.auto_engage]
|
||||
label = "自动互动"
|
||||
description = "自动对人脉网络中的相关帖子点赞和评论"
|
||||
|
||||
[i18n.zh.settings.approval_mode]
|
||||
label = "审批模式"
|
||||
description = "将帖子加入队列等待审核,而非直接发布"
|
||||
|
||||
[i18n.zh.settings.hashtag_count]
|
||||
label = "话题标签数量"
|
||||
description = "每篇帖子包含的话题标签数量"
|
||||
|
||||
[i18n.zh.settings.target_audience]
|
||||
label = "目标受众"
|
||||
description = "内容的主要目标受众"
|
||||
|
||||
[i18n.zh.settings.language]
|
||||
label = "语言"
|
||||
description = "帖子和互动使用的语言"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "LinkedIn Hand"
|
||||
description = "自律型LinkedInマネージャー——プロフィール最適化、コンテンツ作成、ネットワーキング、プロフェッショナルエンゲージメント"
|
||||
category = "コミュニケーション"
|
||||
|
||||
[i18n.ja.settings.content_style]
|
||||
label = "コンテンツスタイル"
|
||||
description = "LinkedIn投稿の語調とスタイル"
|
||||
|
||||
[i18n.ja.settings.post_frequency]
|
||||
label = "投稿頻度"
|
||||
description = "コンテンツの作成・投稿の頻度"
|
||||
|
||||
[i18n.ja.settings.content_topics]
|
||||
label = "コンテンツトピック"
|
||||
description = "作成するコンテンツのトピック(カンマ区切り、例: AI、リーダーシップ、スタートアップ)"
|
||||
|
||||
[i18n.ja.settings.auto_engage]
|
||||
label = "自動エンゲージメント"
|
||||
description = "ネットワーク内の関連投稿に自動でいいねやコメントをする"
|
||||
|
||||
[i18n.ja.settings.approval_mode]
|
||||
label = "承認モード"
|
||||
description = "投稿を直接公開せず、レビュー用キューに追加する"
|
||||
|
||||
[i18n.ja.settings.hashtag_count]
|
||||
label = "ハッシュタグ数"
|
||||
description = "各投稿に含めるハッシュタグの数"
|
||||
|
||||
[i18n.ja.settings.target_audience]
|
||||
label = "ターゲットオーディエンス"
|
||||
description = "コンテンツの主なターゲット層"
|
||||
|
||||
[i18n.ja.settings.language]
|
||||
label = "言語"
|
||||
description = "投稿とエンゲージメントに使用する言語"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de LinkedIn"
|
||||
description = "Gestor autónomo de LinkedIn — optimización de perfil, creación de contenido, networking y engagement profesional"
|
||||
category = "Comunicación"
|
||||
|
||||
[i18n.es.settings.content_style]
|
||||
label = "Estilo de contenido"
|
||||
description = "Voz y tono para las publicaciones de LinkedIn"
|
||||
|
||||
[i18n.es.settings.post_frequency]
|
||||
label = "Frecuencia de publicación"
|
||||
description = "Con qué frecuencia crear y publicar contenido"
|
||||
|
||||
[i18n.es.settings.content_topics]
|
||||
label = "Temas de contenido"
|
||||
description = "Temas sobre los que crear contenido (separados por comas, ej. IA, liderazgo, startups)"
|
||||
|
||||
[i18n.es.settings.auto_engage]
|
||||
label = "Engagement automático"
|
||||
description = "Dar like y comentar automáticamente en publicaciones relevantes de tu red"
|
||||
|
||||
[i18n.es.settings.approval_mode]
|
||||
label = "Modo de aprobación"
|
||||
description = "Poner publicaciones en cola para revisión en lugar de publicarlas directamente"
|
||||
|
||||
[i18n.es.settings.hashtag_count]
|
||||
label = "Cantidad de hashtags"
|
||||
description = "Número de hashtags a incluir por publicación"
|
||||
|
||||
[i18n.es.settings.target_audience]
|
||||
label = "Audiencia objetivo"
|
||||
description = "Audiencia principal para tu contenido"
|
||||
|
||||
[i18n.es.settings.language]
|
||||
label = "Idioma"
|
||||
description = "Idioma para publicaciones e interacciones"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand LinkedIn"
|
||||
description = "Gestionnaire LinkedIn autonome — optimisation de profil, création de contenu, réseautage et engagement professionnel"
|
||||
category = "Communication"
|
||||
|
||||
[i18n.fr.settings.content_style]
|
||||
label = "Style de contenu"
|
||||
description = "Ton et style pour les publications LinkedIn"
|
||||
|
||||
[i18n.fr.settings.post_frequency]
|
||||
label = "Fréquence de publication"
|
||||
description = "Fréquence de création et de publication de contenu"
|
||||
|
||||
[i18n.fr.settings.content_topics]
|
||||
label = "Sujets de contenu"
|
||||
description = "Sujets sur lesquels créer du contenu (séparés par des virgules, ex. IA, leadership, startups)"
|
||||
|
||||
[i18n.fr.settings.auto_engage]
|
||||
label = "Engagement automatique"
|
||||
description = "Aimer et commenter automatiquement les publications pertinentes de votre réseau"
|
||||
|
||||
[i18n.fr.settings.approval_mode]
|
||||
label = "Mode d'approbation"
|
||||
description = "Mettre les publications en file d'attente pour révision au lieu de les publier directement"
|
||||
|
||||
[i18n.fr.settings.hashtag_count]
|
||||
label = "Nombre de hashtags"
|
||||
description = "Nombre de hashtags à inclure par publication"
|
||||
|
||||
[i18n.fr.settings.target_audience]
|
||||
label = "Public cible"
|
||||
description = "Public principal pour votre contenu"
|
||||
|
||||
[i18n.fr.settings.language]
|
||||
label = "Langue"
|
||||
description = "Langue pour les publications et les interactions"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "LinkedIn-Hand"
|
||||
description = "Autonomer LinkedIn-Manager — Profiloptimierung, Content-Erstellung, Networking und professionelles Engagement"
|
||||
category = "Kommunikation"
|
||||
|
||||
[i18n.de.settings.content_style]
|
||||
label = "Inhaltsstil"
|
||||
description = "Ton und Stil für LinkedIn-Beiträge"
|
||||
|
||||
[i18n.de.settings.post_frequency]
|
||||
label = "Veröffentlichungshäufigkeit"
|
||||
description = "Wie oft Inhalte erstellt und veröffentlicht werden"
|
||||
|
||||
[i18n.de.settings.content_topics]
|
||||
label = "Inhaltsthemen"
|
||||
description = "Themen für die Content-Erstellung (kommagetrennt, z.B. KI, Führung, Startups)"
|
||||
|
||||
[i18n.de.settings.auto_engage]
|
||||
label = "Automatisches Engagement"
|
||||
description = "Relevante Beiträge im Netzwerk automatisch liken und kommentieren"
|
||||
|
||||
[i18n.de.settings.approval_mode]
|
||||
label = "Genehmigungsmodus"
|
||||
description = "Beiträge zur Überprüfung in die Warteschlange stellen, anstatt sie direkt zu veröffentlichen"
|
||||
|
||||
[i18n.de.settings.hashtag_count]
|
||||
label = "Anzahl Hashtags"
|
||||
description = "Anzahl der Hashtags pro Beitrag"
|
||||
|
||||
[i18n.de.settings.target_audience]
|
||||
label = "Zielgruppe"
|
||||
description = "Primäre Zielgruppe für Ihre Inhalte"
|
||||
|
||||
[i18n.de.settings.language]
|
||||
label = "Sprache"
|
||||
description = "Sprache für Beiträge und Interaktionen"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "LinkedIn Hand"
|
||||
description = "자율 LinkedIn 관리 — 프로필 최적화, 콘텐츠 제작, 네트워킹 및 전문적 소통"
|
||||
category = "커뮤니케이션"
|
||||
|
||||
[i18n.ko.settings.content_style]
|
||||
label = "콘텐츠 스타일"
|
||||
description = "LinkedIn 게시물의 어조와 스타일"
|
||||
|
||||
[i18n.ko.settings.post_frequency]
|
||||
label = "게시 빈도"
|
||||
description = "콘텐츠를 작성하고 게시하는 주기"
|
||||
|
||||
[i18n.ko.settings.content_topics]
|
||||
label = "콘텐츠 주제"
|
||||
description = "콘텐츠를 작성할 주제 (쉼표로 구분, 예: AI, 리더십, 스타트업)"
|
||||
|
||||
[i18n.ko.settings.auto_engage]
|
||||
label = "자동 소통"
|
||||
description = "네트워크 내 관련 게시물에 자동으로 좋아요 및 댓글"
|
||||
|
||||
[i18n.ko.settings.approval_mode]
|
||||
label = "승인 모드"
|
||||
description = "게시물을 직접 게시하지 않고 대기열에 추가하여 검토"
|
||||
|
||||
[i18n.ko.settings.hashtag_count]
|
||||
label = "해시태그 수"
|
||||
description = "게시물당 포함할 해시태그 수"
|
||||
|
||||
[i18n.ko.settings.target_audience]
|
||||
label = "대상 독자"
|
||||
description = "콘텐츠의 주요 대상 독자"
|
||||
|
||||
[i18n.ko.settings.language]
|
||||
label = "언어"
|
||||
description = "게시물 및 소통에 사용하는 언어"
|
||||
@@ -218,3 +218,753 @@ Before posting any content, classify it:
|
||||
- Credit sources and tag collaborators
|
||||
- Disclose affiliations when discussing products or services
|
||||
- Respect intellectual property and copyright
|
||||
|
||||
---
|
||||
|
||||
## Advanced API Patterns
|
||||
|
||||
### Image Post Creation (Media Upload Flow)
|
||||
|
||||
Posting an image requires a 3-step flow: register upload, upload binary, then create post.
|
||||
|
||||
**Step 1 -- Register the upload**:
|
||||
```bash
|
||||
curl -s -X POST "https://api.linkedin.com/rest/images?action=initializeUpload" \
|
||||
-H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "LinkedIn-Version: 202405" \
|
||||
-d '{
|
||||
"initializeUploadRequest": {
|
||||
"owner": "urn:li:person:MEMBER_ID"
|
||||
}
|
||||
}'
|
||||
```
|
||||
Response contains `uploadUrl` and `image` URN (e.g., `urn:li:image:C4E...`).
|
||||
|
||||
**Step 2 -- Upload the binary**:
|
||||
```bash
|
||||
curl -s -X PUT "$UPLOAD_URL" \
|
||||
-H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
|
||||
-H "Content-Type: image/png" \
|
||||
--data-binary "@/path/to/image.png"
|
||||
```
|
||||
|
||||
**Step 3 -- Create post with image**:
|
||||
```bash
|
||||
curl -s -X POST "https://api.linkedin.com/rest/posts" \
|
||||
-H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "LinkedIn-Version: 202405" \
|
||||
-d '{
|
||||
"author": "urn:li:person:MEMBER_ID",
|
||||
"lifecycleState": "PUBLISHED",
|
||||
"commentary": "Check out our Q3 results!",
|
||||
"visibility": "PUBLIC",
|
||||
"distribution": {"feedDistribution": "MAIN_FEED"},
|
||||
"content": {
|
||||
"media": {
|
||||
"id": "urn:li:image:IMAGE_URN",
|
||||
"title": "Q3 Performance Summary"
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### Document Post Creation (PDF/Carousel)
|
||||
|
||||
LinkedIn "document posts" (carousels) follow the same register-upload-post pattern but use the documents API.
|
||||
|
||||
**Register document upload**:
|
||||
```bash
|
||||
curl -s -X POST "https://api.linkedin.com/rest/documents?action=initializeUpload" \
|
||||
-H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "LinkedIn-Version: 202405" \
|
||||
-d '{
|
||||
"initializeUploadRequest": {
|
||||
"owner": "urn:li:person:MEMBER_ID"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
**Upload the PDF and create post** (same pattern as image -- PUT binary, then POST with `content.media.id` set to the document URN).
|
||||
|
||||
### Article Publishing via API
|
||||
|
||||
**Create an article post** (link article hosted externally):
|
||||
```bash
|
||||
curl -s -X POST "https://api.linkedin.com/rest/posts" \
|
||||
-H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "LinkedIn-Version: 202405" \
|
||||
-d '{
|
||||
"author": "urn:li:person:MEMBER_ID",
|
||||
"lifecycleState": "PUBLISHED",
|
||||
"commentary": "I wrote about why most engineering teams get incident response wrong.\n\nKey insight: the 5-minute rule changes everything.",
|
||||
"visibility": "PUBLIC",
|
||||
"distribution": {"feedDistribution": "MAIN_FEED"},
|
||||
"content": {
|
||||
"article": {
|
||||
"source": "https://yourblog.com/incident-response",
|
||||
"title": "The 5-Minute Rule for Incident Response",
|
||||
"description": "A practical framework for engineering teams"
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
> **Note**: Article-link posts get reduced reach vs native text posts. Prefer putting links in the first comment.
|
||||
|
||||
### Analytics Endpoints
|
||||
|
||||
**Get post statistics (organic)**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
|
||||
-H "LinkedIn-Version: 202405" \
|
||||
"https://api.linkedin.com/rest/organizationalEntityShareStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:ORG_ID&timeIntervals.timeGranularityType=DAY&timeIntervals.timeRange.start=1704067200000&timeIntervals.timeRange.end=1706745600000"
|
||||
```
|
||||
|
||||
**Get share statistics for a specific post**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
|
||||
-H "LinkedIn-Version: 202405" \
|
||||
"https://api.linkedin.com/rest/organizationalEntityShareStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:ORG_ID&shares=urn:li:share:SHARE_ID"
|
||||
```
|
||||
|
||||
Response fields:
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `totalShareStatistics.impressionCount` | Total times the post appeared in feeds |
|
||||
| `totalShareStatistics.uniqueImpressionsCount` | Unique viewers |
|
||||
| `totalShareStatistics.clickCount` | Total clicks (content + read more) |
|
||||
| `totalShareStatistics.likeCount` | Total likes/reactions |
|
||||
| `totalShareStatistics.commentCount` | Total comments |
|
||||
| `totalShareStatistics.shareCount` | Total reposts |
|
||||
| `totalShareStatistics.engagement` | Engagement rate (decimal) |
|
||||
|
||||
**Get follower statistics** (organization pages):
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
|
||||
-H "LinkedIn-Version: 202405" \
|
||||
"https://api.linkedin.com/rest/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:ORG_ID"
|
||||
```
|
||||
|
||||
### Webhook / Notification Patterns
|
||||
|
||||
LinkedIn does not offer real-time webhooks for most events. Use polling instead:
|
||||
|
||||
```
|
||||
Polling strategy:
|
||||
- Post engagement: Poll every 15 minutes for first 4 hours after posting
|
||||
- Mentions/comments: Poll every 5 minutes during engagement_hours
|
||||
- Follower counts: Poll once per day
|
||||
- Analytics: Poll once per day (data lags 24-48 hours)
|
||||
```
|
||||
|
||||
### Error Handling and Rate Limit Retry
|
||||
|
||||
```
|
||||
Rate limit response headers:
|
||||
X-RateLimit-Limit: 100
|
||||
X-RateLimit-Remaining: 0
|
||||
X-RateLimit-Reset: 1706745600
|
||||
|
||||
HTTP 429 response:
|
||||
{"status": 429, "message": "Resource level throttle limit..."}
|
||||
```
|
||||
|
||||
**Retry strategy**:
|
||||
```
|
||||
1. On HTTP 429: Read X-RateLimit-Reset header
|
||||
2. Calculate wait_seconds = reset_timestamp - current_timestamp
|
||||
3. Sleep for wait_seconds + 1 (buffer)
|
||||
4. Retry the request (max 3 retries)
|
||||
5. On 3 consecutive 429s: back off for 15 minutes
|
||||
|
||||
On HTTP 5xx (server error):
|
||||
1. Retry with exponential backoff: 1s, 2s, 4s
|
||||
2. Max 3 retries
|
||||
3. Log failure and queue for later retry
|
||||
|
||||
On HTTP 401 (expired token):
|
||||
1. Trigger OAuth 2.0 refresh flow
|
||||
2. Update stored token
|
||||
3. Retry original request once
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Content Calendar Template
|
||||
|
||||
### Monthly Content Planning Framework
|
||||
|
||||
Organize content around weekly themes that rotate through your content pillars.
|
||||
|
||||
```
|
||||
MONTH: [Month Year]
|
||||
THEME ROTATION:
|
||||
Week 1: [Pillar 1 -- e.g., Engineering Leadership]
|
||||
Week 2: [Pillar 2 -- e.g., Industry Trends]
|
||||
Week 3: [Pillar 3 -- e.g., Career Growth]
|
||||
Week 4: [Pillar 1 deep dive OR seasonal/timely topic]
|
||||
```
|
||||
|
||||
### Weekly Content Schedule
|
||||
|
||||
```
|
||||
WEEK OF [DATE] — Theme: [Weekly Theme]
|
||||
|
||||
Monday:
|
||||
- 8:30 AM: [Personal story] tied to weekly theme
|
||||
Format: Hook + narrative + lesson + question
|
||||
Goal: High engagement to start the week
|
||||
|
||||
Tuesday:
|
||||
- 9:00 AM: [Step-by-step guide] or [How-to]
|
||||
Format: Numbered list with tactical advice
|
||||
Goal: Saves and shares (authority building)
|
||||
|
||||
Wednesday:
|
||||
- 8:30 AM: [Data/insight post] with original analysis
|
||||
Format: Stat + context + your take + question
|
||||
Goal: Credibility and thought leadership
|
||||
|
||||
Thursday:
|
||||
- 9:00 AM: [Contrarian take] or [Industry opinion]
|
||||
Format: Bold statement + reasoning + invitation to debate
|
||||
Goal: Comments and discussion (algorithm boost)
|
||||
|
||||
Friday:
|
||||
- 8:00 AM: [Engagement post] — poll, question, or lightweight personal content
|
||||
Format: Short, conversational, easy to respond to
|
||||
Goal: Community building before weekend
|
||||
```
|
||||
|
||||
### Content Mix Ratios
|
||||
|
||||
| Category | % of Posts | Examples |
|
||||
|----------|-----------|----------|
|
||||
| Educational / Value | 40% | How-tos, frameworks, lessons learned |
|
||||
| Personal / Storytelling | 25% | Career stories, failures, reflections |
|
||||
| Engagement / Discussion | 20% | Questions, polls, contrarian takes |
|
||||
| Promotional / Company | 10% | Product launches, hiring, milestones |
|
||||
| Curated / Commentary | 5% | Industry news with your analysis |
|
||||
|
||||
**Rule**: Never let promotional content exceed 15%. LinkedIn penalizes overtly sales-y accounts.
|
||||
|
||||
### Engagement Windows and Response Strategy
|
||||
|
||||
```
|
||||
Post published at 8:30 AM:
|
||||
Minutes 0-15: Reply to EVERY comment immediately (signals activity to algorithm)
|
||||
Minutes 15-60: Reply within 5 minutes of each new comment
|
||||
Hours 1-4: Reply within 30 minutes
|
||||
Hours 4-24: Reply within 2 hours (during business hours)
|
||||
Day 2+: Reply within 24 hours
|
||||
|
||||
First-comment strategy:
|
||||
- Post your own comment within 2 minutes of publishing
|
||||
- Use it for: link to resource, additional context, question to spark discussion
|
||||
- This comment acts as engagement seed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Analytics & Optimization
|
||||
|
||||
### Key Metrics to Track
|
||||
|
||||
| Metric | Formula | Good Benchmark | Great Benchmark |
|
||||
|--------|---------|----------------|-----------------|
|
||||
| Engagement rate | (reactions + comments + reposts) / impressions | > 2% | > 5% |
|
||||
| Comment rate | comments / impressions | > 0.3% | > 1% |
|
||||
| Follower growth rate | net new followers / total followers per week | > 0.5% | > 2% |
|
||||
| Profile views | weekly profile views trend | Consistent growth | 2x after viral post |
|
||||
| SSI (Social Selling Index) | LinkedIn's built-in score (0-100) | > 50 | > 70 |
|
||||
| Content saves | saves / impressions | > 0.5% | > 2% |
|
||||
| Click-through rate | clicks / impressions | > 1% | > 3% |
|
||||
|
||||
### Engagement Rate Calculation
|
||||
|
||||
```
|
||||
engagement_rate = (reactions + comments + reposts) / impressions * 100
|
||||
|
||||
Example:
|
||||
120 reactions + 35 comments + 8 reposts = 163 engagements
|
||||
163 / 5,200 impressions = 3.13% engagement rate
|
||||
|
||||
Per-post tracking:
|
||||
| Post Date | Topic | Format | Impressions | Eng Rate | Comments |
|
||||
|-----------|-------|--------|-------------|----------|----------|
|
||||
| Mon 03/03 | Leadership | Story | 5,200 | 3.13% | 35 |
|
||||
| Tue 03/04 | AI Tools | How-to | 3,800 | 4.21% | 22 |
|
||||
| Wed 03/05 | Hiring | Data | 2,100 | 2.85% | 12 |
|
||||
```
|
||||
|
||||
### A/B Testing Strategies
|
||||
|
||||
Test one variable at a time across pairs of similar posts:
|
||||
|
||||
| Variable | Option A | Option B | Track |
|
||||
|----------|----------|----------|-------|
|
||||
| Hook style | Question hook | Bold statement hook | Click-through rate |
|
||||
| Post length | Short (< 800 chars) | Long (1200+ chars) | Dwell time, engagement |
|
||||
| Posting time | 8:00 AM | 9:30 AM | Impressions after 4 hours |
|
||||
| CTA type | Question CTA | "Agree? Repost" CTA | Comment rate vs repost rate |
|
||||
| Hashtag count | 3 hashtags | 0 hashtags | Reach beyond network |
|
||||
| Format | Plain text | Text + image | Engagement rate |
|
||||
|
||||
**How to run a test**:
|
||||
1. Pick one variable to test (e.g., posting time)
|
||||
2. Keep everything else constant (same pillar, similar format, similar length)
|
||||
3. Run for 2 weeks (minimum 4 posts per variant)
|
||||
4. Compare average metrics -- ignore outliers
|
||||
5. Adopt the winner and move to next variable
|
||||
|
||||
### Identifying Top-Performing Content Patterns
|
||||
|
||||
After 30+ posts, analyze your data to find patterns:
|
||||
|
||||
```
|
||||
Sort all posts by engagement rate (descending):
|
||||
1. Look at your top 5 posts — what do they share?
|
||||
- Same content pillar?
|
||||
- Same format (story, how-to, contrarian)?
|
||||
- Same hook style?
|
||||
- Similar length range?
|
||||
- Same posting day/time?
|
||||
2. Look at your bottom 5 posts — what went wrong?
|
||||
- External links in body?
|
||||
- Promotional tone?
|
||||
- Published on Friday/weekend?
|
||||
- Weak hook?
|
||||
3. Create your "hit formula":
|
||||
Best combo: [Pillar] + [Format] + [Hook style] + [Day/Time]
|
||||
Example: "Engineering Leadership + Personal Story + Confession Hook + Tuesday 8:30 AM"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Audience Growth Strategies
|
||||
|
||||
### Comment-First Strategy
|
||||
|
||||
The fastest way to grow on LinkedIn is strategic commenting on high-visibility posts.
|
||||
|
||||
**How it works**:
|
||||
1. Identify 15-20 active creators in your niche (10K+ followers)
|
||||
2. Turn on notifications for their posts
|
||||
3. Be among the first 5 comments on their new posts
|
||||
4. Write substantive comments (3-5 sentences) that add genuine value
|
||||
|
||||
**Comment templates for growth**:
|
||||
```
|
||||
Adding a data point:
|
||||
"This resonates. At [Company/Role], we saw [specific metric] when we
|
||||
implemented [related approach]. The key difference was [insight].
|
||||
Curious if others have seen similar results?"
|
||||
|
||||
Respectful counterpoint:
|
||||
"Interesting perspective. I'd push back slightly on [point] — in my
|
||||
experience with [context], the opposite was true because [reason].
|
||||
That said, I think [original point] absolutely holds for [use case]."
|
||||
|
||||
Extending the idea:
|
||||
"Building on this — one thing I'd add is [new angle]. I wrote about
|
||||
this recently and the biggest takeaway was [specific insight].
|
||||
[Question that invites further discussion]?"
|
||||
```
|
||||
|
||||
**Target**: 5-10 thoughtful comments per day during peak hours (8-10 AM).
|
||||
|
||||
### Collaborative Content Patterns
|
||||
|
||||
**Tagging strategy**:
|
||||
- Tag 1-3 people who would genuinely find the content relevant
|
||||
- Always explain WHY you're tagging them (not drive-by tags)
|
||||
- Tag people you've already engaged with (they're more likely to respond)
|
||||
|
||||
```
|
||||
Example post with strategic tags:
|
||||
"I've been thinking about how engineering teams handle on-call rotations.
|
||||
|
||||
After talking to 20+ eng managers, here are the 3 models that actually work:
|
||||
|
||||
1. Follow-the-sun (best for distributed teams)
|
||||
2. Volunteer-first rotation (best for small teams)
|
||||
3. Tiered escalation (best for complex systems)
|
||||
|
||||
@Name1 — your team's approach to #2 was eye-opening.
|
||||
@Name2 — curious if your distributed team uses #1 or something else?
|
||||
|
||||
What model does your team use? Reply with your team size."
|
||||
```
|
||||
|
||||
**Co-creation patterns**:
|
||||
- Interview a peer and post key insights (tag them, they reshare)
|
||||
- "X people I learned from this year" posts (mass tagging, high reshare rate)
|
||||
- Collaborative lists: "Drop your best [resource] in the comments, I'll compile and share"
|
||||
|
||||
### LinkedIn Newsletter Strategy
|
||||
|
||||
Newsletters convert profile visitors into subscribers with direct inbox delivery.
|
||||
|
||||
**Newsletter setup checklist**:
|
||||
```
|
||||
1. Name: Clear, specific, benefit-driven
|
||||
Good: "The Engineering Leader's Playbook"
|
||||
Bad: "My Thoughts on Things"
|
||||
|
||||
2. Cadence: Weekly or biweekly (consistency > frequency)
|
||||
|
||||
3. Format:
|
||||
- 800-1500 words (longer than posts, shorter than blog articles)
|
||||
- One core idea per issue
|
||||
- Actionable takeaways or frameworks
|
||||
- End with a question to drive comments
|
||||
|
||||
4. Promotion:
|
||||
- Announce each issue with a teaser post (don't just auto-share)
|
||||
- Reference newsletter content in regular posts
|
||||
- Cross-promote with other newsletter authors
|
||||
```
|
||||
|
||||
**Newsletter content structure**:
|
||||
```
|
||||
Issue #[N]: [Compelling Title]
|
||||
|
||||
[Hook paragraph -- why this matters NOW]
|
||||
|
||||
[Section 1: The Problem / Context]
|
||||
- 2-3 paragraphs with specific examples
|
||||
|
||||
[Section 2: The Framework / Solution]
|
||||
- Numbered steps or clear model
|
||||
- Real-world application examples
|
||||
|
||||
[Section 3: How to Apply This]
|
||||
- Actionable next steps the reader can take today
|
||||
|
||||
[Closing: Question + CTA]
|
||||
"What's your experience with [topic]? Reply in the comments."
|
||||
"If you found this useful, share it with your team."
|
||||
```
|
||||
|
||||
### LinkedIn Live and Events
|
||||
|
||||
**LinkedIn Live** broadcasts get 7x more reactions and 24x more comments than regular video posts.
|
||||
|
||||
**Live session framework**:
|
||||
```
|
||||
Pre-event (1 week before):
|
||||
- Create LinkedIn Event and post announcement
|
||||
- Send invites to relevant connections
|
||||
- Post 2-3 teaser posts building anticipation
|
||||
|
||||
During event:
|
||||
- Start 2 minutes early for tech check
|
||||
- Open with clear agenda (30 seconds)
|
||||
- Acknowledge live commenters by name
|
||||
- Keep sessions 20-40 minutes
|
||||
|
||||
Post-event:
|
||||
- Post key takeaways within 2 hours
|
||||
- Reply to all comments on the event post
|
||||
- Repurpose recording into 3-5 short clips for future posts
|
||||
```
|
||||
|
||||
**Event types that work**:
|
||||
| Type | Duration | Best For | Frequency |
|
||||
|------|----------|----------|-----------|
|
||||
| AMA (Ask Me Anything) | 30 min | Engagement, authority | Monthly |
|
||||
| Industry deep dive | 20 min | Thought leadership | Biweekly |
|
||||
| Interview / fireside chat | 40 min | Network growth | Monthly |
|
||||
| Quick tip / hot take | 10 min | Visibility | Weekly |
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Thought Leadership Campaign
|
||||
|
||||
**Scenario**: VP of Engineering building authority in "engineering culture" niche.
|
||||
|
||||
**Content pillars**:
|
||||
```
|
||||
Pillar 1: Engineering Management (40%)
|
||||
Pillar 2: Scaling Teams (30%)
|
||||
Pillar 3: Career Advice (20%)
|
||||
Pillar 4: Personal Lessons (10%)
|
||||
```
|
||||
|
||||
**Week 1 posting schedule with sample posts**:
|
||||
|
||||
**Monday 8:30 AM -- Personal Story (Pillar 1)**:
|
||||
```
|
||||
I promoted my worst interviewer to Head of Recruiting.
|
||||
|
||||
Sounds crazy. Here's what happened.
|
||||
|
||||
She kept rejecting candidates everyone else loved.
|
||||
Her "pass rate" was 15%. Team average was 60%.
|
||||
|
||||
But after 12 months, something became clear:
|
||||
|
||||
Her hires had:
|
||||
→ 94% retention rate (team avg: 71%)
|
||||
→ 2.3x faster time to first meaningful contribution
|
||||
→ Zero PIPs in their first year
|
||||
|
||||
She wasn't a bad interviewer.
|
||||
She was the only one actually doing it right.
|
||||
|
||||
The lesson?
|
||||
Measure what matters. Pass rates reward speed.
|
||||
Retention rates reward judgment.
|
||||
|
||||
What's one metric your team optimizes for
|
||||
that might be the wrong one?
|
||||
|
||||
#EngineeringLeadership #Hiring #TechManagement
|
||||
```
|
||||
|
||||
**Tuesday 9:00 AM -- How-To Guide (Pillar 2)**:
|
||||
```
|
||||
How to run a team retrospective that people actually enjoy
|
||||
(not the soul-crushing ones everyone dreads):
|
||||
|
||||
Step 1: Kill the "what went well / what didn't" format
|
||||
→ Use "I wish... I wonder... I'm proud of..." instead
|
||||
|
||||
Step 2: Timebox ruthlessly
|
||||
→ 45 minutes max. If it takes longer, your team is too big for one retro.
|
||||
|
||||
Step 3: One action item per person, max
|
||||
→ A retro with 20 action items produces zero change.
|
||||
→ One item per person = accountability.
|
||||
|
||||
Step 4: Start with appreciation
|
||||
→ First 5 minutes: each person thanks someone else on the team.
|
||||
→ This changes the entire energy of the room.
|
||||
|
||||
Step 5: Rotate the facilitator
|
||||
→ The manager should NOT always run retros.
|
||||
→ It changes what people feel safe saying.
|
||||
|
||||
I've used this format with teams of 5 to teams of 50.
|
||||
|
||||
What's your retro format? Drop it below --
|
||||
I'm always looking for new approaches.
|
||||
|
||||
#Agile #EngineeringCulture #TeamManagement
|
||||
```
|
||||
|
||||
**Wednesday 8:30 AM -- Data + Insight (Pillar 2)**:
|
||||
```
|
||||
We tracked every engineering team meeting for 6 months.
|
||||
|
||||
The data was uncomfortable.
|
||||
|
||||
→ Average engineer: 11.2 hours/week in meetings
|
||||
→ Senior engineers: 16.4 hours/week
|
||||
→ Time spent in meetings that could've been async: 62%
|
||||
|
||||
We cut 40% of recurring meetings.
|
||||
|
||||
Result after 3 months:
|
||||
→ Sprint velocity: +23%
|
||||
→ Engineer satisfaction: +31% (internal survey)
|
||||
→ "Deep work" blocks per week: 2.1 → 4.7
|
||||
|
||||
The surprising part?
|
||||
Nobody missed the deleted meetings.
|
||||
Not one person asked to bring them back.
|
||||
|
||||
If you haven't audited your meeting load recently,
|
||||
you're probably burning 30-40% of your team's capacity.
|
||||
|
||||
What % of your meetings could be an async update?
|
||||
|
||||
#Engineering #Productivity #Leadership
|
||||
```
|
||||
|
||||
**Thursday 9:00 AM -- Contrarian Take (Pillar 3)**:
|
||||
```
|
||||
Unpopular opinion: "Culture fit" interviews should be illegal.
|
||||
|
||||
Here's why:
|
||||
|
||||
Culture fit = "do I want to get a beer with this person?"
|
||||
That's not hiring. That's friend-making.
|
||||
|
||||
What actually matters:
|
||||
→ Values alignment (do they care about the same outcomes?)
|
||||
→ Working style compatibility (async vs sync, docs vs meetings)
|
||||
→ Growth trajectory (will they push the team forward?)
|
||||
|
||||
None of those require "fitting in."
|
||||
|
||||
The best hire I ever made was someone who challenged
|
||||
every assumption we had. They didn't "fit" our culture.
|
||||
|
||||
They made it better.
|
||||
|
||||
Replace "culture fit" with "culture add."
|
||||
|
||||
Agree or disagree? I'd love to hear your take.
|
||||
|
||||
#Hiring #Diversity #EngineeringCulture #Leadership
|
||||
```
|
||||
|
||||
**Friday 8:00 AM -- Engagement Post (Pillar 4)**:
|
||||
```
|
||||
Fill in the blank:
|
||||
|
||||
"The best career advice I ever received was ___________."
|
||||
|
||||
I'll go first:
|
||||
|
||||
"Stop optimizing for your next promotion.
|
||||
Start optimizing for your next learning curve."
|
||||
|
||||
Changed how I made every career decision since.
|
||||
|
||||
Your turn.
|
||||
|
||||
#CareerAdvice #ProfessionalGrowth
|
||||
```
|
||||
|
||||
### Example 2: Company Page Management
|
||||
|
||||
**Scenario**: B2B SaaS company (Series B, 80 employees) managing their LinkedIn company page.
|
||||
|
||||
**Posting cadence**:
|
||||
```
|
||||
Company page: 4-5 posts per week
|
||||
Employee advocacy: 2-3 employees reshare/post per week
|
||||
Executive accounts: CEO + CTO post 2-3x/week each
|
||||
```
|
||||
|
||||
**Weekly company page schedule**:
|
||||
```
|
||||
Monday: Industry insight or thought leadership (educational)
|
||||
Tuesday: Product tip or customer use case (value-driven)
|
||||
Wednesday: Team/culture spotlight (employer branding)
|
||||
Thursday: Data or trend analysis (authority)
|
||||
Friday: Milestone, hiring, or community post (engagement)
|
||||
```
|
||||
|
||||
**Sample company page posts**:
|
||||
|
||||
**Tuesday -- Customer Use Case**:
|
||||
```
|
||||
"We used to spend 3 hours every Monday pulling reports manually."
|
||||
|
||||
That's what @CustomerName's ops team told us last quarter.
|
||||
|
||||
After switching to [Product] automated workflows:
|
||||
→ Report generation: 3 hours → 12 minutes
|
||||
→ Data accuracy: 89% → 99.7%
|
||||
→ Team freed up: 12 hours/week for strategic work
|
||||
|
||||
The best part? They set it up in a single afternoon.
|
||||
|
||||
Read the full story: [link in first comment]
|
||||
|
||||
#DataAutomation #Operations #CustomerSuccess
|
||||
```
|
||||
|
||||
**Wednesday -- Team Culture Spotlight**:
|
||||
```
|
||||
This is Sarah. She joined us as intern #3 two years ago.
|
||||
|
||||
Last week she deployed our new ML pipeline to production.
|
||||
By herself. On a Tuesday. No drama.
|
||||
|
||||
What happened in between:
|
||||
→ Mentored by 4 different senior engineers
|
||||
→ Shipped 47 PRs in her first year
|
||||
→ Gave her first conference talk at 23
|
||||
→ Now leads a team of 3
|
||||
|
||||
We don't hire for credentials.
|
||||
We hire for curiosity and grit.
|
||||
|
||||
Sarah had both.
|
||||
|
||||
We're hiring 5 more engineers just like her.
|
||||
Link in the comments.
|
||||
|
||||
#Hiring #Engineering #StartupCulture #WomenInTech
|
||||
```
|
||||
|
||||
**Employee advocacy tracking**:
|
||||
```
|
||||
| Employee | Role | Posts/Week | Avg Reach | Topics |
|
||||
|----------|------|-----------|-----------|--------|
|
||||
| CEO | Executive | 3 | 8,500 | Vision, industry, leadership |
|
||||
| CTO | Executive | 2 | 5,200 | Technical, architecture, hiring |
|
||||
| VP Eng | Leader | 2 | 3,100 | Engineering culture, management |
|
||||
| DevRel | IC | 3 | 4,800 | Tutorials, product, community |
|
||||
```
|
||||
|
||||
**Analytics tracking cadence**:
|
||||
```
|
||||
Daily: Check post-level engagement (reactions, comments, shares)
|
||||
Weekly: Follower growth, top-performing post, engagement rate trend
|
||||
Monthly: Content audit — which pillars/formats performed best
|
||||
Adjust next month's content mix based on data
|
||||
Quarterly: Competitor benchmarking, SSI review, strategy refresh
|
||||
```
|
||||
|
||||
### Example 3: Job Seeker Profile Optimization Campaign
|
||||
|
||||
**Scenario**: Senior developer transitioning to engineering management role.
|
||||
|
||||
**4-week content plan**:
|
||||
```
|
||||
Week 1: Establish expertise
|
||||
- Post about a technical decision you led and its business impact
|
||||
- Share a "lessons from my first year managing" story
|
||||
- Comment on 10 engineering leadership posts
|
||||
|
||||
Week 2: Demonstrate thought leadership
|
||||
- Publish a how-to post: "How I transitioned from IC to manager"
|
||||
- Share data or a framework you've developed
|
||||
- Start engaging with hiring managers' content in target companies
|
||||
|
||||
Week 3: Build social proof
|
||||
- Post about a mentoring success story (tag the mentee with permission)
|
||||
- Share a "things I wish I knew" post targeting new managers
|
||||
- Request 3-5 recommendations from colleagues and reports
|
||||
|
||||
Week 4: Signal availability
|
||||
- Post about what you're looking for (without desperation)
|
||||
- Engage heavily in target company employees' content
|
||||
- Send personalized connection requests to hiring managers
|
||||
```
|
||||
|
||||
**Sample "open to opportunities" post**:
|
||||
```
|
||||
After 8 years of writing code and 2 years of leading teams,
|
||||
I'm looking for my next engineering management challenge.
|
||||
|
||||
What I bring to the table:
|
||||
→ Scaled a team from 4 to 22 engineers
|
||||
→ Reduced deployment failures by 73% through better process
|
||||
→ Mentored 6 engineers into senior roles
|
||||
→ Built hiring pipelines that maintained 85%+ offer acceptance
|
||||
|
||||
What I'm looking for:
|
||||
→ Series A-C company building something meaningful
|
||||
→ Team of 8-20 engineers who care about craft
|
||||
→ Leadership that values engineering culture, not just velocity
|
||||
|
||||
If your team is growing and you value
|
||||
managers who still understand the code --
|
||||
I'd love to chat.
|
||||
|
||||
DMs are open. Or drop a comment and I'll reach out.
|
||||
|
||||
#OpenToWork #EngineeringManager #Hiring #Leadership
|
||||
```
|
||||
@@ -425,6 +425,241 @@ token_consumption = "high"
|
||||
default_active = false
|
||||
activation_warning = "Predictor hand runs continuously and generates predictions, consuming tokens."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "预测 Hand"
|
||||
description = "自主预测智能体——收集信号、构建推理链、做出校准预测并追踪准确度"
|
||||
category = "数据"
|
||||
|
||||
[i18n.zh.settings.prediction_domain]
|
||||
label = "预测领域"
|
||||
description = "预测的主要关注领域"
|
||||
|
||||
[i18n.zh.settings.time_horizon]
|
||||
label = "时间跨度"
|
||||
description = "预测的前瞻时间范围"
|
||||
|
||||
[i18n.zh.settings.data_sources]
|
||||
label = "数据来源"
|
||||
description = "监控信号的来源类型"
|
||||
|
||||
[i18n.zh.settings.report_frequency]
|
||||
label = "报告频率"
|
||||
description = "生成预测报告的频率"
|
||||
|
||||
[i18n.zh.settings.predictions_per_report]
|
||||
label = "每份报告预测数"
|
||||
description = "每份报告包含的预测条目数量"
|
||||
|
||||
[i18n.zh.settings.track_accuracy]
|
||||
label = "追踪准确度"
|
||||
description = "在预测时间窗口到期后对历史预测进行评分"
|
||||
|
||||
[i18n.zh.settings.confidence_threshold]
|
||||
label = "置信度阈值"
|
||||
description = "纳入预测报告的最低置信度"
|
||||
|
||||
[i18n.zh.settings.contrarian_mode]
|
||||
label = "逆向思维模式"
|
||||
description = "主动寻找并展示与主流共识相反的预测"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "予測 Hand"
|
||||
description = "自律型予測エージェント——シグナル収集、推論チェーン構築、キャリブレーション済み予測、精度追跡"
|
||||
category = "データ"
|
||||
|
||||
[i18n.ja.settings.prediction_domain]
|
||||
label = "予測ドメイン"
|
||||
description = "予測の主な対象分野"
|
||||
|
||||
[i18n.ja.settings.time_horizon]
|
||||
label = "予測期間"
|
||||
description = "どのくらい先まで予測するか"
|
||||
|
||||
[i18n.ja.settings.data_sources]
|
||||
label = "データソース"
|
||||
description = "シグナルを監視するソースの種類"
|
||||
|
||||
[i18n.ja.settings.report_frequency]
|
||||
label = "レポート頻度"
|
||||
description = "予測レポートの生成頻度"
|
||||
|
||||
[i18n.ja.settings.predictions_per_report]
|
||||
label = "レポートあたりの予測数"
|
||||
description = "各レポートに含める予測項目の数"
|
||||
|
||||
[i18n.ja.settings.track_accuracy]
|
||||
label = "精度追跡"
|
||||
description = "予測期間が終了した過去の予測にスコアを付ける"
|
||||
|
||||
[i18n.ja.settings.confidence_threshold]
|
||||
label = "信頼度しきい値"
|
||||
description = "予測をレポートに含めるための最低信頼度"
|
||||
|
||||
[i18n.ja.settings.contrarian_mode]
|
||||
label = "逆張りモード"
|
||||
description = "コンセンサスに反する予測を積極的に探索・提示する"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Predicciones"
|
||||
description = "Predictor autónomo del futuro — recopila señales, construye cadenas de razonamiento, genera predicciones calibradas y rastrea la precisión"
|
||||
category = "Datos"
|
||||
|
||||
[i18n.es.settings.prediction_domain]
|
||||
label = "Dominio de predicción"
|
||||
description = "Dominio principal para las predicciones"
|
||||
|
||||
[i18n.es.settings.time_horizon]
|
||||
label = "Horizonte temporal"
|
||||
description = "Qué tan lejos en el futuro predecir"
|
||||
|
||||
[i18n.es.settings.data_sources]
|
||||
label = "Fuentes de datos"
|
||||
description = "Qué tipos de fuentes monitorear para señales"
|
||||
|
||||
[i18n.es.settings.report_frequency]
|
||||
label = "Frecuencia de informes"
|
||||
description = "Con qué frecuencia generar informes de predicción"
|
||||
|
||||
[i18n.es.settings.predictions_per_report]
|
||||
label = "Predicciones por informe"
|
||||
description = "Número de predicciones a incluir por informe"
|
||||
|
||||
[i18n.es.settings.track_accuracy]
|
||||
label = "Rastrear precisión"
|
||||
description = "Puntuar predicciones pasadas cuando su horizonte temporal expire"
|
||||
|
||||
[i18n.es.settings.confidence_threshold]
|
||||
label = "Umbral de confianza"
|
||||
description = "Confianza mínima para incluir una predicción"
|
||||
|
||||
[i18n.es.settings.contrarian_mode]
|
||||
label = "Modo contrario"
|
||||
description = "Buscar y presentar activamente predicciones contrarias al consenso"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand de Prédictions"
|
||||
description = "Prédicteur autonome — collecte de signaux, construction de chaînes de raisonnement, prédictions calibrées et suivi de la précision"
|
||||
category = "Données"
|
||||
|
||||
[i18n.fr.settings.prediction_domain]
|
||||
label = "Domaine de prédiction"
|
||||
description = "Domaine principal pour les prédictions"
|
||||
|
||||
[i18n.fr.settings.time_horizon]
|
||||
label = "Horizon temporel"
|
||||
description = "Jusqu'où prédire dans le futur"
|
||||
|
||||
[i18n.fr.settings.data_sources]
|
||||
label = "Sources de données"
|
||||
description = "Types de sources à surveiller pour les signaux"
|
||||
|
||||
[i18n.fr.settings.report_frequency]
|
||||
label = "Fréquence des rapports"
|
||||
description = "Fréquence de génération des rapports de prédiction"
|
||||
|
||||
[i18n.fr.settings.predictions_per_report]
|
||||
label = "Prédictions par rapport"
|
||||
description = "Nombre de prédictions à inclure par rapport"
|
||||
|
||||
[i18n.fr.settings.track_accuracy]
|
||||
label = "Suivi de la précision"
|
||||
description = "Évaluer les prédictions passées lorsque leur horizon temporel expire"
|
||||
|
||||
[i18n.fr.settings.confidence_threshold]
|
||||
label = "Seuil de confiance"
|
||||
description = "Confiance minimale pour inclure une prédiction"
|
||||
|
||||
[i18n.fr.settings.contrarian_mode]
|
||||
label = "Mode contraire"
|
||||
description = "Rechercher et présenter activement des prédictions contraires au consensus"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Vorhersage-Hand"
|
||||
description = "Autonomer Vorhersage-Agent — Signalerfassung, Aufbau von Argumentationsketten, kalibrierte Vorhersagen und Genauigkeitsverfolgung"
|
||||
category = "Daten"
|
||||
|
||||
[i18n.de.settings.prediction_domain]
|
||||
label = "Vorhersagedomäne"
|
||||
description = "Hauptdomäne für Vorhersagen"
|
||||
|
||||
[i18n.de.settings.time_horizon]
|
||||
label = "Zeithorizont"
|
||||
description = "Wie weit in die Zukunft vorhergesagt werden soll"
|
||||
|
||||
[i18n.de.settings.data_sources]
|
||||
label = "Datenquellen"
|
||||
description = "Welche Quellentypen auf Signale überwacht werden"
|
||||
|
||||
[i18n.de.settings.report_frequency]
|
||||
label = "Berichtshäufigkeit"
|
||||
description = "Wie oft Vorhersageberichte generiert werden"
|
||||
|
||||
[i18n.de.settings.predictions_per_report]
|
||||
label = "Vorhersagen pro Bericht"
|
||||
description = "Anzahl der Vorhersagen pro Bericht"
|
||||
|
||||
[i18n.de.settings.track_accuracy]
|
||||
label = "Genauigkeitsverfolgung"
|
||||
description = "Vergangene Vorhersagen bewerten, wenn ihr Zeithorizont abläuft"
|
||||
|
||||
[i18n.de.settings.confidence_threshold]
|
||||
label = "Konfidenzschwelle"
|
||||
description = "Mindestvertrauen für die Aufnahme einer Vorhersage"
|
||||
|
||||
[i18n.de.settings.contrarian_mode]
|
||||
label = "Konträrer Modus"
|
||||
description = "Aktiv nach Vorhersagen suchen und präsentieren, die dem Konsens widersprechen"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "예측 Hand"
|
||||
description = "자율 미래 예측 에이전트 — 신호 수집, 추론 체인 구축, 보정된 예측 수행 및 정확도 추적"
|
||||
category = "데이터"
|
||||
|
||||
[i18n.ko.settings.prediction_domain]
|
||||
label = "예측 분야"
|
||||
description = "예측의 주요 관심 분야"
|
||||
|
||||
[i18n.ko.settings.time_horizon]
|
||||
label = "시간 범위"
|
||||
description = "예측의 미래 전망 기간"
|
||||
|
||||
[i18n.ko.settings.data_sources]
|
||||
label = "데이터 소스"
|
||||
description = "신호를 모니터링할 소스 유형"
|
||||
|
||||
[i18n.ko.settings.report_frequency]
|
||||
label = "보고서 빈도"
|
||||
description = "예측 보고서 생성 주기"
|
||||
|
||||
[i18n.ko.settings.predictions_per_report]
|
||||
label = "보고서당 예측 수"
|
||||
description = "각 보고서에 포함할 예측 항목 수"
|
||||
|
||||
[i18n.ko.settings.track_accuracy]
|
||||
label = "정확도 추적"
|
||||
description = "예측 기간 만료 후 과거 예측에 대한 점수 평가"
|
||||
|
||||
[i18n.ko.settings.confidence_threshold]
|
||||
label = "신뢰도 임계값"
|
||||
description = "예측 보고서에 포함하기 위한 최소 신뢰도"
|
||||
|
||||
[i18n.ko.settings.contrarian_mode]
|
||||
label = "역발상 모드"
|
||||
description = "주류 컨센서스에 반하는 예측을 적극적으로 탐색하고 제시"
|
||||
@@ -184,6 +184,591 @@ PREDICTION: [Specific, falsifiable claim]
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Corporate Acquisition
|
||||
|
||||
**Question**: "Will Acme Corp be acquired within 12 months?" (asked January 2025)
|
||||
|
||||
```
|
||||
PREDICTION: Acme Corp (mid-cap SaaS, $2B market cap) will be acquired by January 2026
|
||||
|
||||
1. REFERENCE CLASS (Outside View)
|
||||
Base rate: ~5-7% of publicly traded mid-cap SaaS companies receive
|
||||
acquisition offers in any given 12-month period.
|
||||
Reference examples:
|
||||
- Splunk acquired by Cisco (2023) — similar scale, strategic buyer
|
||||
- Figma attempted acquisition by Adobe (2022) — regulatory block
|
||||
- Nuance acquired by Microsoft (2021) — vertical SaaS, strategic fit
|
||||
- Mandiant acquired by Google (2022) — security vertical
|
||||
- Cvent acquired by Blackstone (2021) — PE buyout at depressed valuation
|
||||
|
||||
Starting probability: 6%
|
||||
|
||||
2. SPECIFIC EVIDENCE (Inside View)
|
||||
Signals FOR (+):
|
||||
a. Board hired Goldman Sachs as advisor (leaked filing)
|
||||
— strength: STRONG — adjustment: +20%
|
||||
(Companies that retain M&A advisors complete a transaction ~40% of the time)
|
||||
b. CEO sold 30% of personal holdings in Q4 (SEC filing)
|
||||
— strength: MODERATE — adjustment: +5%
|
||||
c. Two major competitors acquired in past 18 months (market consolidation)
|
||||
— strength: MODERATE — adjustment: +8%
|
||||
d. Revenue growth decelerated from 35% to 18% YoY (earnings report)
|
||||
— strength: MODERATE — adjustment: +5%
|
||||
(Slower-growth companies more likely to accept acquisition offers)
|
||||
|
||||
Signals AGAINST (-):
|
||||
a. Founder still holds 25% voting control and has said "we're building for
|
||||
the long term" (recent interview)
|
||||
— strength: STRONG — adjustment: -12%
|
||||
b. Stock price at all-time high — acquirer must pay steep premium
|
||||
— strength: MODERATE — adjustment: -5%
|
||||
c. Current antitrust environment — FTC blocking more deals
|
||||
— strength: WEAK — adjustment: -3%
|
||||
|
||||
3. SYNTHESIS
|
||||
Starting probability (base rate): 6%
|
||||
Signals for: +20% +5% +8% +5% = +38%
|
||||
Signals against: -12% -5% -3% = -20%
|
||||
Net adjustment: +18%
|
||||
Raw probability: 24%
|
||||
|
||||
Sanity check: ~1 in 4 feels right given the strong M&A advisor signal
|
||||
balanced against founder control.
|
||||
Final probability: 25%
|
||||
|
||||
4. KEY ASSUMPTIONS
|
||||
- Goldman engagement is for M&A (not debt restructuring):
|
||||
If wrong, probability drops to 8%
|
||||
- Founder is willing to sell at the right price:
|
||||
If wrong (founder vetoes any deal), probability drops to 3%
|
||||
- Regulatory environment doesn't tighten further:
|
||||
If wrong, probability drops to 18%
|
||||
|
||||
5. RESOLUTION
|
||||
Date: January 31, 2026
|
||||
Criteria: Definitive merger agreement announced (not just rumors)
|
||||
Data source: SEC EDGAR (8-K filing), Bloomberg terminal
|
||||
```
|
||||
|
||||
### Example 2: Technology Adoption
|
||||
|
||||
**Question**: "Will WebAssembly (Wasm) reach mainstream server-side adoption by 2027?"
|
||||
|
||||
```
|
||||
PREDICTION: >20% of new cloud-deployed services will use Wasm runtimes by
|
||||
end of 2027
|
||||
|
||||
1. REFERENCE CLASS (Outside View)
|
||||
Technology adoption lifecycle (Rogers curve):
|
||||
- Innovators (2.5%) → Early Adopters (13.5%) → Early Majority (34%)
|
||||
- Crossing from Early Adopters to Early Majority typically takes 3-5 years
|
||||
after first production deployments
|
||||
- First serious server-side Wasm deployments: ~2022 (Fermyon, Cosmonic)
|
||||
- Current status (2025): Late Early Adopter stage
|
||||
|
||||
Historical analogues for infrastructure tech adoption:
|
||||
- Containers (Docker 2013 → mainstream 2017-2018): ~4-5 years
|
||||
- Kubernetes (2014 → mainstream 2018-2019): ~4-5 years
|
||||
- Serverless (Lambda 2014 → mainstream 2018-2020): ~4-6 years
|
||||
|
||||
Base rate for "infrastructure tech reaching 20% adoption within 5 years
|
||||
of first production use": ~30%
|
||||
|
||||
Starting probability: 30%
|
||||
|
||||
2. SPECIFIC EVIDENCE (Inside View)
|
||||
Signals FOR (+):
|
||||
a. WASI standard maturing — WASI Preview 2 shipped, component model
|
||||
stabilizing (W3C working group)
|
||||
— strength: STRONG — adjustment: +8%
|
||||
b. Major cloud providers offering Wasm runtimes (Fastly, Cloudflare Workers,
|
||||
Azure, AWS exploring)
|
||||
— strength: STRONG — adjustment: +10%
|
||||
c. Docker adding Wasm support natively (announced 2022, shipping)
|
||||
— strength: MODERATE — adjustment: +5%
|
||||
|
||||
Signals AGAINST (-):
|
||||
a. Ecosystem still fragmented — multiple competing runtimes, toolchain gaps
|
||||
— strength: STRONG — adjustment: -10%
|
||||
b. Containers already "good enough" for most workloads — weak forcing
|
||||
function to switch
|
||||
— strength: STRONG — adjustment: -8%
|
||||
c. Wasm language support uneven — great for Rust/C++, mediocre for Python/JS
|
||||
— strength: MODERATE — adjustment: -5%
|
||||
|
||||
Leading indicators to track:
|
||||
- CNCF survey: % of respondents evaluating/using Wasm
|
||||
- Job postings mentioning Wasm (Indeed/LinkedIn trend)
|
||||
- GitHub stars and contributors for top Wasm runtimes (wasmtime, wasmer)
|
||||
- WASI spec milestone dates vs planned dates
|
||||
|
||||
3. SYNTHESIS
|
||||
Starting probability (base rate): 30%
|
||||
Signals for: +8% +10% +5% = +23%
|
||||
Signals against: -10% -8% -5% = -23%
|
||||
Net adjustment: 0%
|
||||
Final probability: 30%
|
||||
|
||||
Interpretation: The positive and negative signals roughly cancel out.
|
||||
The base rate from analogous infrastructure technologies holds.
|
||||
This is genuinely uncertain — the "chasm" crossing is the key risk.
|
||||
|
||||
4. KEY ASSUMPTIONS
|
||||
- "Mainstream" defined as >20% of NEW deployments (not total installed base)
|
||||
- WASI component model reaches 1.0 stable by mid-2026
|
||||
If delayed beyond 2026: probability drops to 15%
|
||||
- No competing paradigm emerges (e.g., eBPF expanding scope):
|
||||
If strong competitor: probability drops to 20%
|
||||
|
||||
5. RESOLUTION
|
||||
Date: December 31, 2027
|
||||
Criteria: CNCF annual survey shows >20% respondents using Wasm in production
|
||||
Data source: CNCF Annual Survey, Datadog Container Report
|
||||
```
|
||||
|
||||
### Example 3: Geopolitical Forecast
|
||||
|
||||
**Question**: "Will US-China trade tensions escalate significantly in 2025?"
|
||||
(Defined as: new tariffs >25% on >$100B of goods, or export controls expanded
|
||||
to 3+ new technology categories)
|
||||
|
||||
```
|
||||
PREDICTION: Significant escalation of US-China trade tensions in 2025
|
||||
|
||||
1. REFERENCE CLASS (Outside View)
|
||||
Historical trade conflict escalation pattern:
|
||||
- US-China trade relations since 2018: escalation occurred in 4 of 7 years
|
||||
- In election year +1 (new/returning administration): escalation rate ~60%
|
||||
- Trade wars historically escalate in steps, with retaliation cycles
|
||||
|
||||
Starting probability: 55%
|
||||
|
||||
2. SPECIFIC EVIDENCE (Inside View)
|
||||
Signals FOR (+):
|
||||
a. Administration rhetoric on China hawkish across both parties
|
||||
— strength: STRONG — adjustment: +10%
|
||||
b. Semiconductor export controls already expanding (ASML, Tokyo Electron)
|
||||
— strength: STRONG — adjustment: +8%
|
||||
c. China retaliating with rare earth export restrictions
|
||||
— strength: MODERATE — adjustment: +5%
|
||||
|
||||
Signals AGAINST (-):
|
||||
a. Business lobbying against further tariffs (Chamber of Commerce, farm lobby)
|
||||
— strength: MODERATE — adjustment: -5%
|
||||
b. Inflation concerns create political cost for tariffs
|
||||
— strength: MODERATE — adjustment: -5%
|
||||
c. Diplomatic channels active (recent bilateral meetings)
|
||||
— strength: WEAK — adjustment: -3%
|
||||
|
||||
Scenario mapping:
|
||||
┌─────────────────────────┬─────────────┬────────────────────┐
|
||||
│ Scenario │ Probability │ Key trigger │
|
||||
├─────────────────────────┼─────────────┼────────────────────┤
|
||||
│ Major escalation │ 25% │ Taiwan crisis or │
|
||||
│ (new tariffs + controls │ │ tech IP theft case │
|
||||
│ + retaliatory cycle) │ │ │
|
||||
├─────────────────────────┼─────────────┼────────────────────┤
|
||||
│ Moderate escalation │ 40% │ Incremental tariff │
|
||||
│ (meets our threshold) │ │ increases + 1-2 │
|
||||
│ │ │ new export controls│
|
||||
├─────────────────────────┼─────────────┼────────────────────┤
|
||||
│ Status quo / minor │ 30% │ Diplomatic deals, │
|
||||
│ changes │ │ election distraction│
|
||||
├─────────────────────────┼─────────────┼────────────────────┤
|
||||
│ De-escalation │ 5% │ Grand bargain │
|
||||
│ (reduced tariffs) │ │ (historically rare)│
|
||||
└─────────────────────────┴─────────────┴────────────────────┘
|
||||
|
||||
P(meets our escalation threshold) = 25% + 40% = 65%
|
||||
|
||||
3. SYNTHESIS
|
||||
Starting probability (base rate): 55%
|
||||
Signals for: +10% +8% +5% = +23%
|
||||
Signals against: -5% -5% -3% = -13%
|
||||
Net adjustment: +10%
|
||||
Raw probability: 65%
|
||||
|
||||
Cross-check with scenario mapping: 65% — consistent.
|
||||
Final probability: 65%
|
||||
|
||||
4. KEY ASSUMPTIONS
|
||||
- No major geopolitical crisis (Taiwan strait) that causes extreme
|
||||
escalation or extreme restraint: If crisis occurs, split to
|
||||
80% (escalation) or 20% (restraint/avoidance)
|
||||
- US economy remains stable: If recession hits, probability drops
|
||||
to 45% (political cost of tariffs rises)
|
||||
- China does not make major trade concessions preemptively:
|
||||
If it does, probability drops to 30%
|
||||
|
||||
5. RESOLUTION
|
||||
Date: December 31, 2025
|
||||
Criteria: Cumulative new tariffs >25% on >$100B goods OR export controls
|
||||
expanded to 3+ new technology categories (per USTR/BIS announcements)
|
||||
Data source: USTR tariff schedule, BIS Entity List updates, Congressional
|
||||
Research Service reports
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fermi Estimation Techniques
|
||||
|
||||
Fermi estimation is the art of making reasonable order-of-magnitude guesses
|
||||
by breaking unknowable questions into smaller, estimable pieces.
|
||||
|
||||
### Step-by-Step Process
|
||||
|
||||
```
|
||||
1. DEFINE the quantity you want to estimate
|
||||
→ Be specific about units, scope, and timeframe
|
||||
|
||||
2. DECOMPOSE into factors you can estimate independently
|
||||
→ Prefer multiplication chains: A × B × C
|
||||
→ Each factor should be something you can reason about
|
||||
|
||||
3. ESTIMATE each factor
|
||||
→ Use round numbers (powers of 10 when possible)
|
||||
→ State your confidence range for each factor
|
||||
|
||||
4. MULTIPLY and sanity-check
|
||||
→ Does the result pass the "smell test"?
|
||||
→ Cross-check with any known anchors
|
||||
|
||||
5. STATE your uncertainty
|
||||
→ Fermi estimates are typically accurate within 1 order of magnitude
|
||||
→ Give a range: [estimate / 3, estimate × 3] is a reasonable default
|
||||
```
|
||||
|
||||
### Common Reference Anchors
|
||||
|
||||
Keep these memorized for quick estimation:
|
||||
|
||||
```
|
||||
POPULATION
|
||||
World: ~8 billion
|
||||
US: ~340 million
|
||||
EU: ~450 million
|
||||
China: ~1.4 billion
|
||||
India: ~1.4 billion
|
||||
|
||||
ECONOMICS
|
||||
World GDP: ~$100 trillion
|
||||
US GDP: ~$28 trillion
|
||||
US median household: ~$75,000/year
|
||||
US federal budget: ~$6.5 trillion
|
||||
S&P 500 total cap: ~$45 trillion
|
||||
|
||||
TIME
|
||||
Seconds in a day: ~86,400 (~10^5)
|
||||
Seconds in a year: ~31.5 million (~3 × 10^7)
|
||||
Working hours/year: ~2,000
|
||||
|
||||
TECHNOLOGY
|
||||
Global internet users: ~5.5 billion
|
||||
Global smartphone users: ~4.5 billion
|
||||
AWS annual revenue: ~$90 billion
|
||||
Global IT spending: ~$5 trillion
|
||||
GitHub developers: ~100 million
|
||||
|
||||
INDUSTRY SIZES (annual, global)
|
||||
Cloud computing: ~$600 billion
|
||||
Semiconductor: ~$600 billion
|
||||
Pharmaceutical: ~$1.5 trillion
|
||||
Automotive: ~$3 trillion
|
||||
Agriculture: ~$3 trillion
|
||||
E-commerce: ~$6 trillion
|
||||
```
|
||||
|
||||
### Worked Fermi Examples
|
||||
|
||||
**Example A: Estimating the TAM for an AI code review tool**
|
||||
|
||||
```
|
||||
Question: What is the annual TAM for an AI-powered code review SaaS?
|
||||
|
||||
Decomposition:
|
||||
TAM = (Number of professional developers)
|
||||
× (% who do code reviews regularly)
|
||||
× (willingness to pay for tooling)
|
||||
× (average annual price)
|
||||
|
||||
Estimates:
|
||||
Professional developers worldwide: ~30 million
|
||||
(GitHub has 100M accounts, but ~30% are professional, and
|
||||
not all professionals use GitHub)
|
||||
|
||||
% who do code reviews: ~60%
|
||||
(Standard in companies > 50 engineers, less common in small shops)
|
||||
|
||||
Target market (teams that would buy SaaS): ~40%
|
||||
(Enterprise and mid-market; small teams use free tools)
|
||||
|
||||
Annual price per seat: ~$300/year
|
||||
(Comparable: GitHub Copilot ~$200, Snyk ~$400, middle ground)
|
||||
|
||||
Calculation:
|
||||
30M × 0.60 × 0.40 × $300 = $2.16 billion
|
||||
|
||||
Sanity check:
|
||||
- GitHub revenue ~$2B (broader product, ~4M paid users)
|
||||
- Snyk valued at $7B (code security, related space)
|
||||
- $2B TAM is plausible for a focused code review tool
|
||||
|
||||
Result: ~$2 billion TAM (range: $700M to $6B)
|
||||
```
|
||||
|
||||
**Example B: Estimating daily active queries to a search engine**
|
||||
|
||||
```
|
||||
Question: How many search queries does Google process per day?
|
||||
|
||||
Decomposition:
|
||||
Queries/day = (Internet users who use Google)
|
||||
× (searches per user per day)
|
||||
|
||||
Estimates:
|
||||
Global internet users: ~5.5 billion
|
||||
Google market share: ~90%
|
||||
Google users: 5.5B × 0.90 = ~5 billion
|
||||
But not all use it daily: ~50% daily active rate
|
||||
Daily active Google searchers: ~2.5 billion
|
||||
|
||||
Searches per active user per day: ~3-4
|
||||
(Some people search 10+ times, many search once or not at all)
|
||||
|
||||
Calculation:
|
||||
2.5 billion × 3.5 = ~8.5 billion queries/day
|
||||
|
||||
Sanity check:
|
||||
Published figure (Google): ~8.5 billion searches/day (2024)
|
||||
Our estimate nailed it — sometimes Fermi estimation gets lucky.
|
||||
|
||||
Result: ~8.5 billion/day (range: 3B to 25B)
|
||||
```
|
||||
|
||||
### Order of Magnitude Sanity Checks
|
||||
|
||||
After any estimate, verify it makes sense:
|
||||
|
||||
```
|
||||
CHECK 1: Per-person reasonableness
|
||||
Divide by relevant population. Is the per-person number realistic?
|
||||
"$50B market ÷ 340M Americans = $147/person" — plausible?
|
||||
|
||||
CHECK 2: Comparison to known quantities
|
||||
Is your estimate bigger or smaller than things you know?
|
||||
"Our estimate of X is $3B — that's 5% of AWS revenue. Reasonable?"
|
||||
|
||||
CHECK 3: Growth rate implied
|
||||
If you're estimating a future state, what annual growth rate is implied?
|
||||
>50% sustained growth for >3 years is extremely rare.
|
||||
|
||||
CHECK 4: Upper bound test
|
||||
What is the theoretical maximum? Is your estimate within it?
|
||||
"Total possible customers × maximum price = ceiling"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prediction Market Patterns
|
||||
|
||||
### Interpreting Market Prices as Probabilities
|
||||
|
||||
Prediction market prices map to probabilities, but with important caveats:
|
||||
|
||||
```
|
||||
Market price $0.65 for "Event X occurs"
|
||||
→ Naive interpretation: 65% probability
|
||||
→ Adjusted interpretation: depends on market quality
|
||||
|
||||
Adjustment factors:
|
||||
Liquid market (Polymarket, Metaculus with many forecasters):
|
||||
Price ≈ true probability (±3-5%)
|
||||
|
||||
Thin market (<50 traders, <$10K volume):
|
||||
Price is noisy — treat as ±15% uncertainty
|
||||
A $0.65 price could represent 50-80% true probability
|
||||
|
||||
Binary vs. multi-outcome:
|
||||
Binary markets are more reliable
|
||||
Multi-outcome markets often have probabilities summing to >100%
|
||||
(overround) — normalize before interpreting
|
||||
```
|
||||
|
||||
### Common Prediction Market Biases
|
||||
|
||||
| Bias | Description | Impact | Correction |
|
||||
|------|-------------|--------|------------|
|
||||
| Favorite-longshot | Favorites underpriced, longshots overpriced | Longshot events appear ~2-3x more likely than they are | If market says 5%, true probability may be 2-3% |
|
||||
| Recency | Recent events dominate pricing | Probability spikes after news, then slowly reverts | Wait 24-48h after major news before trusting market prices |
|
||||
| Liquidity premium | Illiquid contracts trade at a discount | Prices biased toward 50% in thin markets | Weight liquid markets more heavily |
|
||||
| Expiration clustering | Prices converge to 0 or 1 near expiration | Mid-probability contracts vanish near deadline | Most useful signal is months before resolution |
|
||||
| Hedging distortion | Traders hedging other positions, not expressing beliefs | Prices reflect risk management, not pure probability | Cross-reference with non-market forecasts |
|
||||
|
||||
### Aggregation Methods
|
||||
|
||||
When combining multiple probability estimates (markets, experts, models):
|
||||
|
||||
```
|
||||
SIMPLE AVERAGE
|
||||
P = (P1 + P2 + P3) / 3
|
||||
Use when: Sources are roughly equally credible
|
||||
Weakness: Susceptible to outliers
|
||||
|
||||
MEDIAN
|
||||
P = middle value of sorted estimates
|
||||
Use when: One source might be badly miscalibrated
|
||||
Weakness: Ignores magnitude of disagreement
|
||||
|
||||
TRIMMED MEAN
|
||||
Drop highest and lowest, average the rest
|
||||
P = average(P2 ... Pn-1) after sorting
|
||||
Use when: 5+ sources, want outlier robustness
|
||||
|
||||
EXTREMIZED AVERAGE
|
||||
P_avg = simple average
|
||||
P_extremized = P_avg^a / (P_avg^a + (1-P_avg)^a), where a > 1
|
||||
Typical a = 1.5 to 2.5 (more extremizing with more independent sources)
|
||||
Use when: Sources are genuinely independent (not reading each other)
|
||||
Rationale: If 5 independent sources all say 70%, the true probability
|
||||
is likely higher than 70% — shared info should push further from 50%
|
||||
|
||||
CONFIDENCE-WEIGHTED AVERAGE
|
||||
P = Σ(wi × Pi) / Σ(wi)
|
||||
where wi = track record score or source reliability
|
||||
Use when: Sources have known, differing track records
|
||||
```
|
||||
|
||||
### When Markets Beat Experts (and Vice Versa)
|
||||
|
||||
```
|
||||
MARKETS TEND TO WIN when:
|
||||
✓ Large, liquid, diverse participant pool
|
||||
✓ Question is well-defined with clear resolution criteria
|
||||
✓ Information is widely distributed (no single expert has edge)
|
||||
✓ Time horizon is 1 month to 2 years
|
||||
Examples: Election outcomes, product launch dates, economic indicators
|
||||
|
||||
EXPERTS TEND TO WIN when:
|
||||
✓ Question requires deep domain-specific knowledge
|
||||
✓ Market is thin or participants lack domain context
|
||||
✓ Very long time horizons (>5 years) — markets discount distant futures
|
||||
✓ Novel situations with no historical market precedent
|
||||
Examples: Technical feasibility, scientific breakthroughs, niche regulation
|
||||
|
||||
BEST PRACTICE: Use both
|
||||
Start with the market price, then adjust using expert insight.
|
||||
Treat the market as the prior and expert analysis as an update.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Update Protocol
|
||||
|
||||
### Bayesian Updating Worked Example
|
||||
|
||||
```
|
||||
SCENARIO: You predicted 30% chance that Company Z launches Product A in Q1.
|
||||
New evidence: A leaked internal slide shows a Q1 launch timeline.
|
||||
|
||||
STEP 1: State the prior
|
||||
P(launch in Q1) = 0.30
|
||||
|
||||
STEP 2: Assess the evidence
|
||||
E = leaked slide showing Q1 timeline
|
||||
How likely is this evidence if the launch IS happening in Q1?
|
||||
P(E | launch) = 0.85
|
||||
(Internal slides usually reflect real plans, but plans change)
|
||||
How likely is this evidence if the launch is NOT in Q1?
|
||||
P(E | no launch) = 0.15
|
||||
(Could be outdated slide, aspirational, or decoy)
|
||||
|
||||
STEP 3: Calculate the likelihood ratio
|
||||
LR = P(E | launch) / P(E | no launch) = 0.85 / 0.15 = 5.67
|
||||
|
||||
STEP 4: Convert prior to odds, multiply, convert back
|
||||
Prior odds = 0.30 / 0.70 = 0.429
|
||||
Posterior odds = 0.429 × 5.67 = 2.43
|
||||
Posterior probability = 2.43 / (1 + 2.43) = 0.71
|
||||
|
||||
STEP 5: State the update
|
||||
Prior: 30% → Posterior: 71%
|
||||
Update magnitude: +41 percentage points
|
||||
This is a LARGE update, appropriate because the evidence (internal
|
||||
planning document) is strong and directly relevant.
|
||||
```
|
||||
|
||||
### Evidence Strength Classification
|
||||
|
||||
How much to update based on different types of evidence:
|
||||
|
||||
```
|
||||
EVIDENCE TIER 1 — Large update (likelihood ratio 5-20x)
|
||||
→ Official announcement or regulatory filing
|
||||
→ Confirmed internal document (not rumor)
|
||||
→ Directly observed outcome of prerequisite event
|
||||
→ Multiple independent strong sources confirming same fact
|
||||
Typical update: ±15-30 percentage points
|
||||
|
||||
EVIDENCE TIER 2 — Moderate update (likelihood ratio 2-5x)
|
||||
→ Credible journalist report with named sources
|
||||
→ Statistical data that changes the base rate
|
||||
→ Expert with strong track record changing their view
|
||||
→ Structural/policy change that alters incentives
|
||||
Typical update: ±5-15 percentage points
|
||||
|
||||
EVIDENCE TIER 3 — Small update (likelihood ratio 1.2-2x)
|
||||
→ Rumor from semi-credible source
|
||||
→ Anecdotal evidence (single data point)
|
||||
→ Social media sentiment shift
|
||||
→ Expert opinion without new information
|
||||
Typical update: ±2-5 percentage points
|
||||
|
||||
EVIDENCE TIER 4 — Negligible update (likelihood ratio ~1x)
|
||||
→ Repetition of previously known information
|
||||
→ Pundit opinion with no domain expertise
|
||||
→ Vague statement open to multiple interpretations
|
||||
→ Evidence equally consistent with both outcomes
|
||||
Typical update: ±0-2 percentage points (or skip entirely)
|
||||
```
|
||||
|
||||
### When to Make Large vs. Small Updates
|
||||
|
||||
```
|
||||
MAKE A LARGE UPDATE when:
|
||||
• Evidence directly addresses your key uncertainty
|
||||
• The source has a strong track record on this topic
|
||||
• The evidence would be very surprising if your prediction were correct
|
||||
(or very unsurprising if it were wrong)
|
||||
• Multiple independent signals shift in the same direction simultaneously
|
||||
|
||||
MAKE A SMALL UPDATE when:
|
||||
• Evidence is tangentially related to your prediction
|
||||
• The source's reliability is uncertain
|
||||
• The evidence is consistent with multiple interpretations
|
||||
• You've already incorporated similar evidence
|
||||
|
||||
RESIST UPDATING when:
|
||||
• The "evidence" is just someone restating the consensus
|
||||
• A vivid anecdote feels compelling but carries no statistical weight
|
||||
• You're reacting emotionally (fear, excitement) rather than analytically
|
||||
• The evidence source has an obvious incentive to mislead
|
||||
```
|
||||
|
||||
### Common Updating Mistakes
|
||||
|
||||
| Mistake | Description | Fix |
|
||||
|---------|-------------|-----|
|
||||
| Over-updating on vivid events | A dramatic single event shifts your view by 20+ points when the base rate barely moved | Ask: "Does this event actually change the base rate, or just my emotional state?" |
|
||||
| Under-updating on base rate changes | New data shows the reference class frequency shifted, but you keep your old anchor | Periodically re-derive the base rate from scratch instead of only adjusting incrementally |
|
||||
| Asymmetric updating | Updating strongly on confirming evidence, weakly on disconfirming evidence | Force yourself to calculate the likelihood ratio for disconfirming evidence explicitly |
|
||||
| Double-counting | Updating on a news article, then updating again on a tweet quoting the same article | Track the original source — if two signals share the same root cause, count once |
|
||||
| Failure to update | Knowing the evidence should change your view but not bothering because your current number "feels right" | Set calendar reminders to review active predictions monthly with fresh evidence |
|
||||
| Stampede updating | A prediction market spikes, causing you to rush your update to match | Market moves are data, not commands — assess independently, then compare |
|
||||
|
||||
---
|
||||
|
||||
## Prediction Tracking & Scoring
|
||||
|
||||
### Prediction Ledger Format
|
||||
|
||||
@@ -423,6 +423,241 @@ frequency = "hourly"
|
||||
token_consumption = "medium"
|
||||
default_active = false
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "Reddit Hand"
|
||||
description = "自主 Reddit 管理——监控子版块、发布内容、回复帖子并追踪 Karma 和互动"
|
||||
category = "通信"
|
||||
|
||||
[i18n.zh.settings.subreddits]
|
||||
label = "子版块"
|
||||
description = "要监控的子版块列表(逗号分隔,例如 rust,programming,machinelearning)"
|
||||
|
||||
[i18n.zh.settings.monitor_mode]
|
||||
label = "监控模式"
|
||||
description = "在监控的子版块中追踪哪些内容"
|
||||
|
||||
[i18n.zh.settings.auto_reply]
|
||||
label = "自动回复"
|
||||
description = "自动回复相关的帖子和评论"
|
||||
|
||||
[i18n.zh.settings.post_frequency]
|
||||
label = "发布频率"
|
||||
description = "创建原创帖子的频率"
|
||||
|
||||
[i18n.zh.settings.content_style]
|
||||
label = "内容风格"
|
||||
description = "帖子和回复的语气和风格"
|
||||
|
||||
[i18n.zh.settings.approval_mode]
|
||||
label = "审批模式"
|
||||
description = "将帖子和回复加入队列等待审核,而非直接发布"
|
||||
|
||||
[i18n.zh.settings.min_karma_to_post]
|
||||
label = "最低发帖 Karma"
|
||||
description = "仅在账户拥有至少此数量 Karma 的子版块中发帖"
|
||||
|
||||
[i18n.zh.settings.max_reply_depth]
|
||||
label = "最大回复深度"
|
||||
description = "回复的最大评论嵌套深度(深层嵌套的可见度较低)"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Reddit"
|
||||
description = "Gestor autónomo de Reddit — monitorea subreddits, publica contenido, responde en hilos y rastrea karma e interacciones"
|
||||
category = "Comunicación"
|
||||
|
||||
[i18n.es.settings.subreddits]
|
||||
label = "Subreddits"
|
||||
description = "Lista de subreddits a monitorear separados por comas (ej. rust,programming,machinelearning)"
|
||||
|
||||
[i18n.es.settings.monitor_mode]
|
||||
label = "Modo de monitoreo"
|
||||
description = "Qué rastrear en los subreddits monitoreados"
|
||||
|
||||
[i18n.es.settings.auto_reply]
|
||||
label = "Respuesta automática"
|
||||
description = "Responder automáticamente a publicaciones y comentarios relevantes"
|
||||
|
||||
[i18n.es.settings.post_frequency]
|
||||
label = "Frecuencia de publicación"
|
||||
description = "Con qué frecuencia crear publicaciones originales"
|
||||
|
||||
[i18n.es.settings.content_style]
|
||||
label = "Estilo de contenido"
|
||||
description = "Tono y enfoque para publicaciones y respuestas"
|
||||
|
||||
[i18n.es.settings.approval_mode]
|
||||
label = "Modo de aprobación"
|
||||
description = "Poner publicaciones y respuestas en cola para revisión en lugar de publicarlas directamente"
|
||||
|
||||
[i18n.es.settings.min_karma_to_post]
|
||||
label = "Karma mínimo para publicar"
|
||||
description = "Solo publicar en subreddits donde la cuenta tenga al menos este nivel de karma"
|
||||
|
||||
[i18n.es.settings.max_reply_depth]
|
||||
label = "Profundidad máxima de respuesta"
|
||||
description = "Profundidad máxima del hilo de comentarios para responder (los hilos más profundos tienen menos visibilidad)"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "Reddit Hand"
|
||||
description = "自律型Redditマネージャー——サブレディットの監視、コンテンツ投稿、スレッドへの返信、Karmaとエンゲージメントの追跡"
|
||||
category = "コミュニケーション"
|
||||
|
||||
[i18n.ja.settings.subreddits]
|
||||
label = "サブレディット"
|
||||
description = "監視するサブレディットのリスト(カンマ区切り、例: rust,programming,machinelearning)"
|
||||
|
||||
[i18n.ja.settings.monitor_mode]
|
||||
label = "監視モード"
|
||||
description = "監視対象のサブレディットで追跡する内容"
|
||||
|
||||
[i18n.ja.settings.auto_reply]
|
||||
label = "自動返信"
|
||||
description = "関連する投稿やコメントに自動で返信する"
|
||||
|
||||
[i18n.ja.settings.post_frequency]
|
||||
label = "投稿頻度"
|
||||
description = "オリジナル投稿を作成する頻度"
|
||||
|
||||
[i18n.ja.settings.content_style]
|
||||
label = "コンテンツスタイル"
|
||||
description = "投稿と返信のトーンとアプローチ"
|
||||
|
||||
[i18n.ja.settings.approval_mode]
|
||||
label = "承認モード"
|
||||
description = "投稿や返信を直接公開せず、レビュー用キューに追加する"
|
||||
|
||||
[i18n.ja.settings.min_karma_to_post]
|
||||
label = "投稿に必要な最低Karma"
|
||||
description = "アカウントが最低このKarmaを持つサブレディットでのみ投稿する"
|
||||
|
||||
[i18n.ja.settings.max_reply_depth]
|
||||
label = "最大返信深度"
|
||||
description = "返信するコメントスレッドの最大ネスト深度(深いスレッドほど可視性が低い)"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand Reddit"
|
||||
description = "Gestionnaire Reddit autonome — surveille les subreddits, publie du contenu, répond dans les fils et suit le karma et l'engagement"
|
||||
category = "Communication"
|
||||
|
||||
[i18n.fr.settings.subreddits]
|
||||
label = "Subreddits"
|
||||
description = "Liste de subreddits à surveiller séparés par des virgules (ex. rust,programming,machinelearning)"
|
||||
|
||||
[i18n.fr.settings.monitor_mode]
|
||||
label = "Mode de surveillance"
|
||||
description = "Ce qu'il faut suivre dans les subreddits surveillés"
|
||||
|
||||
[i18n.fr.settings.auto_reply]
|
||||
label = "Réponse automatique"
|
||||
description = "Répondre automatiquement aux publications et commentaires pertinents"
|
||||
|
||||
[i18n.fr.settings.post_frequency]
|
||||
label = "Fréquence de publication"
|
||||
description = "Fréquence de création de publications originales"
|
||||
|
||||
[i18n.fr.settings.content_style]
|
||||
label = "Style de contenu"
|
||||
description = "Ton et approche pour les publications et réponses"
|
||||
|
||||
[i18n.fr.settings.approval_mode]
|
||||
label = "Mode d'approbation"
|
||||
description = "Mettre les publications et réponses en file d'attente pour révision au lieu de les publier directement"
|
||||
|
||||
[i18n.fr.settings.min_karma_to_post]
|
||||
label = "Karma minimum pour publier"
|
||||
description = "Ne publier que dans les subreddits où le compte possède au moins ce niveau de karma"
|
||||
|
||||
[i18n.fr.settings.max_reply_depth]
|
||||
label = "Profondeur maximale de réponse"
|
||||
description = "Profondeur maximale d'imbrication des commentaires pour répondre (les fils plus profonds ont moins de visibilité)"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Reddit-Hand"
|
||||
description = "Autonomer Reddit-Manager — überwacht Subreddits, postet Inhalte, antwortet in Threads und verfolgt Karma und Engagement"
|
||||
category = "Kommunikation"
|
||||
|
||||
[i18n.de.settings.subreddits]
|
||||
label = "Subreddits"
|
||||
description = "Kommagetrennte Liste der zu überwachenden Subreddits (z.B. rust,programming,machinelearning)"
|
||||
|
||||
[i18n.de.settings.monitor_mode]
|
||||
label = "Überwachungsmodus"
|
||||
description = "Was in den überwachten Subreddits verfolgt werden soll"
|
||||
|
||||
[i18n.de.settings.auto_reply]
|
||||
label = "Automatische Antwort"
|
||||
description = "Automatisch auf relevante Beiträge und Kommentare antworten"
|
||||
|
||||
[i18n.de.settings.post_frequency]
|
||||
label = "Veröffentlichungshäufigkeit"
|
||||
description = "Wie oft originale Beiträge erstellt werden"
|
||||
|
||||
[i18n.de.settings.content_style]
|
||||
label = "Inhaltsstil"
|
||||
description = "Ton und Ansatz für Beiträge und Antworten"
|
||||
|
||||
[i18n.de.settings.approval_mode]
|
||||
label = "Genehmigungsmodus"
|
||||
description = "Beiträge und Antworten zur Überprüfung in die Warteschlange stellen, anstatt sie direkt zu veröffentlichen"
|
||||
|
||||
[i18n.de.settings.min_karma_to_post]
|
||||
label = "Mindest-Karma zum Posten"
|
||||
description = "Nur in Subreddits posten, in denen das Konto mindestens dieses Karma-Level hat"
|
||||
|
||||
[i18n.de.settings.max_reply_depth]
|
||||
label = "Maximale Antworttiefe"
|
||||
description = "Maximale Verschachtelungstiefe für Kommentarantworten (tiefere Threads haben geringere Sichtbarkeit)"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "Reddit Hand"
|
||||
description = "자율 Reddit 관리 — 서브레딧 모니터링, 콘텐츠 게시, 스레드 댓글 및 카르마와 참여도 추적"
|
||||
category = "커뮤니케이션"
|
||||
|
||||
[i18n.ko.settings.subreddits]
|
||||
label = "서브레딧"
|
||||
description = "모니터링할 서브레딧 목록 (쉼표로 구분, 예: rust,programming,machinelearning)"
|
||||
|
||||
[i18n.ko.settings.monitor_mode]
|
||||
label = "모니터링 모드"
|
||||
description = "모니터링 대상 서브레딧에서 추적할 콘텐츠"
|
||||
|
||||
[i18n.ko.settings.auto_reply]
|
||||
label = "자동 답글"
|
||||
description = "관련 게시물과 댓글에 자동으로 답글 작성"
|
||||
|
||||
[i18n.ko.settings.post_frequency]
|
||||
label = "게시 빈도"
|
||||
description = "원본 게시물 작성 주기"
|
||||
|
||||
[i18n.ko.settings.content_style]
|
||||
label = "콘텐츠 스타일"
|
||||
description = "게시물과 답글의 어조와 접근 방식"
|
||||
|
||||
[i18n.ko.settings.approval_mode]
|
||||
label = "승인 모드"
|
||||
description = "게시물과 답글을 직접 게시하지 않고 대기열에 추가하여 검토"
|
||||
|
||||
[i18n.ko.settings.min_karma_to_post]
|
||||
label = "최소 게시 카르마"
|
||||
description = "계정이 최소 이만큼의 카르마를 보유한 서브레딧에서만 게시"
|
||||
|
||||
[i18n.ko.settings.max_reply_depth]
|
||||
label = "최대 답글 깊이"
|
||||
description = "답글 작성의 최대 댓글 중첩 깊이 (깊은 중첩일수록 노출도 감소)"
|
||||
@@ -247,3 +247,768 @@ Monitor account standing:
|
||||
- Build karma organically through genuine engagement
|
||||
- Avoid posting too frequently (triggers spam filters)
|
||||
- Diversify activity across multiple subreddits
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Product Launch on Reddit
|
||||
|
||||
**Scenario**: You are launching a developer CLI tool and want to generate awareness on Reddit.
|
||||
|
||||
**Phase 1 — Subreddit Research (Week 1-2 before launch)**
|
||||
|
||||
Identify target subreddits and evaluate each:
|
||||
```
|
||||
Target subreddits (prioritized):
|
||||
1. r/commandline — 350k members, accepts tool announcements, requires demo/screenshot
|
||||
2. r/programming — 5M members, strict anti-marketing, only accepts substantial technical posts
|
||||
3. r/opensource — 200k members, friendly to launches, requires repo link
|
||||
4. r/devtools — 50k members, niche but highly targeted
|
||||
5. r/sideproject — 100k members, launch-friendly, expects "what I built" framing
|
||||
```
|
||||
|
||||
Fetch subreddit rules programmatically:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/commandline/about/rules"
|
||||
```
|
||||
|
||||
**Phase 2 — Karma Building (Week 1-2 before launch)**
|
||||
|
||||
Before posting about your product, build credibility:
|
||||
```
|
||||
Day 1-3: Answer questions in r/commandline and r/programming (3-5 helpful comments/day)
|
||||
Day 4-7: Share a useful tip or short guide unrelated to your product
|
||||
Day 8-10: Engage in discussions, upvote good content, reply to others' posts
|
||||
Day 11-14: Share a technical deep-dive related to your product's domain (not the product itself)
|
||||
```
|
||||
|
||||
**Phase 3 — Launch Posts (Launch Day)**
|
||||
|
||||
Craft posts per subreddit culture:
|
||||
|
||||
For **r/sideproject** (casual, story-driven):
|
||||
```
|
||||
Title: "I built a CLI tool that does X — here's what I learned"
|
||||
Body:
|
||||
- Paragraph on the problem and motivation
|
||||
- Short demo (gif/video link or code block)
|
||||
- What went wrong during development
|
||||
- Link to repo
|
||||
- "Would love feedback on X"
|
||||
```
|
||||
|
||||
For **r/programming** (technical, anti-fluff):
|
||||
```
|
||||
Title: "X: an open-source CLI for Y written in Rust [with benchmarks]"
|
||||
Body:
|
||||
- Link directly to repo or blog post with technical depth
|
||||
- Performance comparison table
|
||||
- Architecture decisions
|
||||
- NO "please star my repo" language
|
||||
```
|
||||
|
||||
For **r/commandline** (practical, demo-focused):
|
||||
```
|
||||
Title: "X — does Y in Z seconds from your terminal"
|
||||
Body:
|
||||
- Install instructions (one-liner)
|
||||
- Usage example with real output
|
||||
- Screenshot or asciinema link
|
||||
- Comparison to existing tools
|
||||
```
|
||||
|
||||
**Phase 4 — Engagement (Launch Day + 48 hours)**
|
||||
|
||||
Response templates:
|
||||
|
||||
| Comment Type | Response Strategy |
|
||||
|-------------|-------------------|
|
||||
| "How does this compare to Z?" | Honest comparison table, acknowledge Z's strengths |
|
||||
| "Why not just use Z?" | Explain specific use cases where yours differs, no FUD |
|
||||
| "Found a bug" | Thank them, ask for details, open GitHub issue immediately |
|
||||
| "This is spam" | Do NOT argue. Briefly state this is your project and you're here to discuss |
|
||||
| "Great work!" | Thank them, ask what feature they'd want next |
|
||||
| Feature request | Acknowledge, add to roadmap, link to issue tracker |
|
||||
|
||||
**Phase 5 — Follow-Up (Week after launch)**
|
||||
|
||||
- Reply to every comment within 12 hours
|
||||
- Post an update in r/sideproject if you hit a milestone (e.g., "Hit 500 stars, here's what I changed based on Reddit feedback")
|
||||
- Do NOT cross-post the same content -- write fresh posts per subreddit
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Community Monitoring and Sentiment Tracking
|
||||
|
||||
**Scenario**: You manage a brand's Reddit presence and need to track mentions, sentiment, and emerging issues.
|
||||
|
||||
**Step 1 — Set Up Monitoring Queries**
|
||||
|
||||
Search for brand mentions across Reddit:
|
||||
```bash
|
||||
# Search all of Reddit for brand mentions
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/search?q=%22BrandName%22+OR+%22brandname%22&sort=new&limit=25&t=day"
|
||||
```
|
||||
|
||||
Monitor specific subreddits where your audience lives:
|
||||
```bash
|
||||
# Monitor r/technology for relevant topics
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/technology/search?q=BrandName&restrict_sr=on&sort=new&limit=25&t=week"
|
||||
```
|
||||
|
||||
**Step 2 — Sentiment Classification**
|
||||
|
||||
Categorize each mention into:
|
||||
```
|
||||
POSITIVE — Praise, recommendation, success story
|
||||
NEUTRAL — Factual mention, question, comparison
|
||||
NEGATIVE — Complaint, bug report, frustration
|
||||
CRITICAL — Security concern, viral complaint, legal risk
|
||||
```
|
||||
|
||||
Scoring signals from Reddit data:
|
||||
```
|
||||
score > 100 + sentiment=NEGATIVE → High-priority alert (viral complaint)
|
||||
score > 50 + sentiment=POSITIVE → Amplification opportunity
|
||||
num_comments > 20 + any sentiment → Active discussion, monitor closely
|
||||
upvote_ratio < 0.5 → Controversial, may escalate
|
||||
```
|
||||
|
||||
**Step 3 — Alert Thresholds**
|
||||
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| CRITICAL mention with score > 10 | Immediate alert to team |
|
||||
| 3+ NEGATIVE mentions in 24 hours | Trend alert, investigate root cause |
|
||||
| NEGATIVE post in subreddit > 500k members | Monitor hourly for 48 hours |
|
||||
| Competitor comparison post trending | Prepare factual response (do NOT post defensively) |
|
||||
|
||||
**Step 4 — Weekly Report Template**
|
||||
|
||||
```
|
||||
## Reddit Weekly Report — [Date Range]
|
||||
|
||||
### Summary
|
||||
- Total mentions: X (up/down Y% from last week)
|
||||
- Sentiment breakdown: X% positive, Y% neutral, Z% negative
|
||||
- Top subreddits: r/sub1 (N mentions), r/sub2 (N mentions)
|
||||
|
||||
### Trending Topics
|
||||
1. [Topic] — [Subreddit] — [Sentiment] — [Link]
|
||||
2. ...
|
||||
|
||||
### Action Items
|
||||
- [ ] Respond to [specific thread] — negative sentiment, high visibility
|
||||
- [ ] Engage with [specific thread] — positive, amplification opportunity
|
||||
|
||||
### Competitor Activity
|
||||
- [Competitor A]: N mentions, trending topics: ...
|
||||
- [Competitor B]: N mentions, trending topics: ...
|
||||
|
||||
### Metrics
|
||||
| Metric | This Week | Last Week | Change |
|
||||
|--------|-----------|-----------|--------|
|
||||
| Total mentions | | | |
|
||||
| Positive % | | | |
|
||||
| Avg post score | | | |
|
||||
| Response time (hrs) | | | |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 3: AMA (Ask Me Anything) Management
|
||||
|
||||
**Scenario**: You are organizing an AMA for a tech CEO in r/technology.
|
||||
|
||||
**Preparation (2 Weeks Before)**
|
||||
|
||||
1. Contact the subreddit moderators:
|
||||
- Message the mod team through modmail (not individual DMs)
|
||||
- Propose date, time, and AMA subject
|
||||
- Ask about specific rules for AMAs (verification, scheduling, flair)
|
||||
- Confirm the post format they expect
|
||||
|
||||
2. Schedule for peak engagement:
|
||||
```
|
||||
Recommended AMA times (US-centric subreddits):
|
||||
- Tuesday-Thursday, 11:00 AM - 1:00 PM EST
|
||||
- Avoid: weekends, holidays, major news days
|
||||
- Post the AMA thread 30-60 minutes before the host starts answering
|
||||
```
|
||||
|
||||
3. Prepare the AMA post:
|
||||
```
|
||||
Title: "I'm [Name], [Role] at [Company]. [One-line hook]. AMA!"
|
||||
|
||||
Body:
|
||||
- Brief intro (2-3 sentences about credentials)
|
||||
- Why this AMA is happening (new product, milestone, event)
|
||||
- Proof/verification (link to tweet, photo with timestamp)
|
||||
- "I'll start answering at [TIME] [TIMEZONE]. Ask me anything!"
|
||||
- Links to relevant context (website, blog post, prior work)
|
||||
```
|
||||
|
||||
**During the AMA (2-3 Hours)**
|
||||
|
||||
Real-time engagement strategy:
|
||||
```
|
||||
1. Sort comments by "best" and "new" alternately every 15 minutes
|
||||
2. Answer top-voted questions first (these set the tone)
|
||||
3. Answer at least 20-30 questions in a 2-hour session
|
||||
4. Mix short answers with detailed ones — avoid walls of text for every question
|
||||
5. Skip hostile/troll questions silently — do NOT acknowledge them
|
||||
6. For tough questions: answer honestly or say "I can't discuss that yet"
|
||||
7. Upvote good questions (even tough ones) — shows good faith
|
||||
```
|
||||
|
||||
Response length guide:
|
||||
| Question Type | Response Length |
|
||||
|--------------|----------------|
|
||||
| Simple factual | 1-2 sentences |
|
||||
| Technical deep-dive | 2-3 paragraphs |
|
||||
| Personal/funny | 1-2 sentences, match the tone |
|
||||
| Critical/tough | 2-3 sentences, direct and honest |
|
||||
| Off-topic | Brief redirect or polite decline |
|
||||
|
||||
**Follow-Up (24-48 Hours After)**
|
||||
|
||||
- Post an edit to the original AMA: "Thanks everyone! I answered [N] questions. Check back — I'll try to answer a few more this week."
|
||||
- Answer 5-10 more highly-upvoted questions that were missed
|
||||
- Share the AMA link on other platforms (Twitter, LinkedIn) to drive continued engagement
|
||||
- Compile a "best of" summary with links to the strongest Q&A exchanges
|
||||
|
||||
---
|
||||
|
||||
## Advanced API Patterns
|
||||
|
||||
### Pagination Handling
|
||||
|
||||
Reddit uses cursor-based pagination with `after` and `before` fullnames.
|
||||
|
||||
**Paginate through subreddit posts**:
|
||||
```bash
|
||||
# Page 1
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/new?limit=100"
|
||||
# Response includes: "after": "t3_abc123"
|
||||
|
||||
# Page 2
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/new?limit=100&after=t3_abc123"
|
||||
# Response includes: "after": "t3_def456" (or null if last page)
|
||||
|
||||
# Page 3
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/new?limit=100&after=t3_def456"
|
||||
```
|
||||
|
||||
Pagination rules:
|
||||
- `limit` max is 100 per request
|
||||
- `after` returns items chronologically older than the given fullname
|
||||
- `before` returns items chronologically newer (useful for "check for new posts since last poll")
|
||||
- When `after` is `null` in the response, you have reached the last page
|
||||
- Reddit caps listing depth at ~1000 items regardless of pagination
|
||||
|
||||
**Paginate backward (newer items)**:
|
||||
```bash
|
||||
# Get posts newer than a known fullname
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/new?limit=25&before=t3_abc123"
|
||||
```
|
||||
|
||||
### Flair Management
|
||||
|
||||
**Get available flairs for a subreddit**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/api/link_flair_v2"
|
||||
```
|
||||
|
||||
**Submit a post with flair**:
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
-d "sr=SUBREDDIT&kind=self&title=TITLE&text=BODY&flair_id=FLAIR_ID&flair_text=FLAIR_TEXT" \
|
||||
"https://oauth.reddit.com/api/submit"
|
||||
```
|
||||
|
||||
**Set flair on an existing post** (requires mod or post author permissions):
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
-d "link=t3_POST_ID&flair_template_id=FLAIR_ID" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/api/selectflair"
|
||||
```
|
||||
|
||||
### Moderation Endpoints
|
||||
|
||||
These require moderator permissions on the target subreddit.
|
||||
|
||||
**Get moderation queue**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/about/modqueue?limit=25"
|
||||
```
|
||||
|
||||
**Approve a post/comment**:
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
-d "id=FULLNAME" \
|
||||
"https://oauth.reddit.com/api/approve"
|
||||
```
|
||||
|
||||
**Remove a post/comment**:
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
-d "id=FULLNAME&spam=false" \
|
||||
"https://oauth.reddit.com/api/remove"
|
||||
```
|
||||
|
||||
**Get moderation log**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/about/log?limit=25&type=removelink"
|
||||
```
|
||||
|
||||
**Distinguish a comment as moderator**:
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
-d "id=FULLNAME&how=yes" \
|
||||
"https://oauth.reddit.com/api/distinguish"
|
||||
```
|
||||
|
||||
### Multi-Subreddit Monitoring
|
||||
|
||||
**Monitor multiple subreddits in a single request**:
|
||||
```bash
|
||||
# Combine subreddits with "+" for a merged feed
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/python+rust+golang/new?limit=50"
|
||||
```
|
||||
|
||||
**Search across multiple subreddits**:
|
||||
```bash
|
||||
# Use the subreddit field in search to restrict
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/search?q=BrandName+subreddit%3Apython+OR+subreddit%3Arust&sort=new&limit=25"
|
||||
```
|
||||
|
||||
**Get subreddit metadata for comparison**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/about"
|
||||
```
|
||||
Key fields in response: `subscribers`, `active_user_count`, `created_utc`, `public_description`, `submit_text`, `submission_type`.
|
||||
|
||||
### Polling Strategies for Real-Time Awareness
|
||||
|
||||
Reddit has no webhook support. Use polling with these patterns:
|
||||
|
||||
**Efficient polling loop**:
|
||||
```
|
||||
1. Fetch /r/SUBREDDIT/new?limit=10 every 60 seconds
|
||||
2. Store the fullname of the newest item seen
|
||||
3. On next poll, use ?before=LAST_SEEN_FULLNAME to get only new items
|
||||
4. If response is empty, no new posts — sleep and retry
|
||||
5. If response has items, process them and update LAST_SEEN_FULLNAME
|
||||
```
|
||||
|
||||
**Polling frequency by priority**:
|
||||
| Monitoring Type | Poll Interval | Endpoint |
|
||||
|----------------|---------------|----------|
|
||||
| Brand crisis monitoring | 30-60 seconds | /search?q=brand&sort=new |
|
||||
| Subreddit new posts | 60-120 seconds | /r/SUB/new |
|
||||
| Comment replies to own posts | 120 seconds | /message/inbox |
|
||||
| Competitor mentions | 300 seconds | /search?q=competitor&sort=new |
|
||||
| Weekly trend analysis | Once daily | /r/SUB/top?t=day |
|
||||
|
||||
**Respect rate limits while polling**:
|
||||
```
|
||||
At 30 requests/minute (app-only auth):
|
||||
- 1 subreddit at 60s interval = 1 req/min → can monitor ~25 subreddits
|
||||
- 1 search query at 60s interval = 1 req/min
|
||||
- Reserve 5 req/min for ad-hoc queries
|
||||
- Total budget: 30 req/min, plan accordingly
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Subreddit Analysis Framework
|
||||
|
||||
### Evaluating a Subreddit Before Posting
|
||||
|
||||
Before investing effort in any subreddit, run this assessment:
|
||||
|
||||
**Step 1 — Pull subreddit metadata**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/about" | python3 -c "
|
||||
import sys, json
|
||||
d = json.load(sys.stdin)['data']
|
||||
print(f'Subscribers: {d[\"subscribers\"]:,}')
|
||||
print(f'Active now: {d[\"active_user_count\"]:,}')
|
||||
print(f'Created: {d[\"created_utc\"]}')
|
||||
print(f'Type: {d[\"submission_type\"]}')
|
||||
print(f'Description: {d[\"public_description\"][:200]}')
|
||||
"
|
||||
```
|
||||
|
||||
**Step 2 — Measure actual engagement** (not just subscriber count):
|
||||
|
||||
```bash
|
||||
# Get top 25 hot posts and examine their scores and comment counts
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/hot?limit=25"
|
||||
```
|
||||
|
||||
Calculate from the response:
|
||||
```
|
||||
Engagement Score = median(post_scores) * median(num_comments)
|
||||
Activity Ratio = active_user_count / subscribers
|
||||
Health Indicator = (posts_per_day > 5) AND (Activity Ratio > 0.001)
|
||||
```
|
||||
|
||||
**Step 3 — Subreddit quality scorecard**:
|
||||
|
||||
| Factor | Good Sign | Bad Sign |
|
||||
|--------|-----------|----------|
|
||||
| Active/subscriber ratio | > 0.1% | < 0.01% |
|
||||
| Median hot post score | > 50 | < 10 |
|
||||
| Median comment count | > 10 | < 3 |
|
||||
| Posts per day | 5-50 | < 1 or > 500 (noise) |
|
||||
| Mod activity | Active modqueue, clear rules | No rules, spam in feed |
|
||||
| Top post age | Within last 24h | Weeks old (dead subreddit) |
|
||||
| Account age requirements | Reasonable (7 days) | None (spam-prone) or extreme (1 year) |
|
||||
|
||||
### Peak Engagement Hours by Subreddit Type
|
||||
|
||||
Optimal posting times vary by audience. All times in EST:
|
||||
|
||||
| Subreddit Type | Peak Hours | Peak Days | Reasoning |
|
||||
|---------------|------------|-----------|-----------|
|
||||
| Tech/Programming | 9-11 AM EST | Tue-Thu | Developers browse during morning coffee |
|
||||
| Business/Startup | 7-9 AM EST | Mon-Wed | Professionals check before work |
|
||||
| Gaming | 6-10 PM EST | Fri-Sun | After work/school |
|
||||
| Science/Academic | 10 AM-12 PM EST | Mon-Wed | Researchers between tasks |
|
||||
| Lifestyle/Hobby | 12-2 PM EST, 7-9 PM EST | Any | Lunch breaks and evenings |
|
||||
| News/Politics | 7-9 AM EST | Mon-Fri | Morning news cycle |
|
||||
| Finance/Crypto | 8-10 AM EST | Mon-Fri | Pre-market and market open |
|
||||
|
||||
To measure a specific subreddit's peak hours:
|
||||
```bash
|
||||
# Pull the last 100 posts and extract their timestamps
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/r/SUBREDDIT/new?limit=100"
|
||||
# Parse created_utc for each post and bucket by hour-of-day
|
||||
# Cross-reference with score to find high-score hours, not just high-volume hours
|
||||
```
|
||||
|
||||
### Competitor Presence Analysis
|
||||
|
||||
**Step 1 — Search for competitor mentions**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/search?q=%22CompetitorName%22&sort=new&t=month&limit=100"
|
||||
```
|
||||
|
||||
**Step 2 — Build a competitor activity profile**:
|
||||
```
|
||||
For each competitor, track:
|
||||
- Which subreddits they are mentioned in (and by whom -- users vs the company)
|
||||
- Frequency of mentions (per week)
|
||||
- Sentiment of mentions (positive / neutral / negative)
|
||||
- Whether they have official accounts engaging in threads
|
||||
- Common complaints about them (your opportunity)
|
||||
- Common praise for them (your benchmark)
|
||||
```
|
||||
|
||||
**Step 3 — Competitor comparison matrix**:
|
||||
| Metric | Your Brand | Competitor A | Competitor B |
|
||||
|--------|-----------|-------------|-------------|
|
||||
| Weekly mentions | | | |
|
||||
| Positive sentiment % | | | |
|
||||
| Subreddits present in | | | |
|
||||
| Official account activity | | | |
|
||||
| Top complaint theme | | | |
|
||||
| Top praise theme | | | |
|
||||
|
||||
### Content Format Preferences by Subreddit Type
|
||||
|
||||
| Subreddit Type | Preferred Format | Avoid |
|
||||
|---------------|-----------------|-------|
|
||||
| Technical (r/programming, r/rust) | Long-form text, code blocks, benchmarks | Short posts, images without context |
|
||||
| Q&A (r/AskReddit, r/askscience) | Concise questions, detailed answers | Link-only posts |
|
||||
| Showcase (r/sideproject, r/webdev) | Screenshots, demos, before/after | Text-only without visuals |
|
||||
| News (r/technology, r/science) | Link to source with summary comment | Self-post opinion pieces |
|
||||
| Discussion (r/startups, r/cscareerquestions) | Personal experience, specific details | Generic advice, platitudes |
|
||||
| Meme-friendly (r/ProgrammerHumor) | Images, short and punchy | Long text posts |
|
||||
|
||||
---
|
||||
|
||||
## Growth & Reputation Building
|
||||
|
||||
### Karma Building Strategies (Comment-First Approach)
|
||||
|
||||
New accounts or accounts entering a new subreddit should follow the comment-first approach:
|
||||
|
||||
**Week 1-2: Listen and respond**
|
||||
```
|
||||
1. Sort by "new" in your target subreddits
|
||||
2. Find questions you can genuinely answer
|
||||
3. Write substantive, helpful comments (3+ sentences with specifics)
|
||||
4. Respond to 3-5 threads per day
|
||||
5. Do NOT mention your product, company, or project at all
|
||||
```
|
||||
|
||||
**Week 3-4: Establish presence**
|
||||
```
|
||||
1. Start sharing relevant resources (not yours) that help the community
|
||||
2. Engage in discussions about trends and opinions in your domain
|
||||
3. Build recognition by being consistently helpful
|
||||
4. Your username should start becoming familiar to regulars
|
||||
```
|
||||
|
||||
**Week 5+: Contribute original content**
|
||||
```
|
||||
1. Share a technical write-up, tutorial, or analysis (unrelated to your product)
|
||||
2. If well-received, you have earned the trust to occasionally mention your work
|
||||
3. Always frame self-promotional content as "I built X" (transparent) not "Check out X" (spammy)
|
||||
4. Maintain the 10:1 ratio — 10 helpful contributions for every 1 self-promotional post
|
||||
```
|
||||
|
||||
Karma accumulation benchmarks:
|
||||
| Milestone | Unlocks |
|
||||
|-----------|---------|
|
||||
| 10 comment karma | Bypass most anti-spam filters |
|
||||
| 50 comment karma | Reduced posting cooldowns |
|
||||
| 100+ comment karma in a subreddit | Trusted contributor status in some subreddits |
|
||||
| 1000+ total karma | Access to r/lounge and some restricted subreddits |
|
||||
|
||||
### Building Authority in Niche Subreddits
|
||||
|
||||
Authority is built through consistency and expertise, not volume:
|
||||
|
||||
1. **Pick 3-5 subreddits maximum** -- spreading across 20 subreddits builds no authority anywhere
|
||||
2. **Develop a recognizable voice** -- consistent formatting, depth of answers, specific expertise area
|
||||
3. **Answer the hard questions** -- skip the easy ones that 10 people will answer; tackle the ones that require real expertise
|
||||
4. **Follow up on your own answers** -- if someone asks a follow-up, respond promptly
|
||||
5. **Cite sources and show work** -- "I benchmarked this myself, here are the numbers" is worth 100x "I think X is faster"
|
||||
6. **Accept corrections gracefully** -- being wrong publicly and handling it well builds more trust than never being wrong
|
||||
|
||||
### Cross-Posting Etiquette and Strategy
|
||||
|
||||
Cross-posting (sharing a post from one subreddit to another) has specific norms:
|
||||
|
||||
**Do:**
|
||||
- Use Reddit's built-in cross-post feature (preserves attribution)
|
||||
- Cross-post to subreddits where the content genuinely fits
|
||||
- Add a comment explaining why it is relevant to the new subreddit
|
||||
- Wait at least a few hours between cross-posts (avoid appearing spammy)
|
||||
|
||||
**Don't:**
|
||||
- Cross-post to more than 2-3 subreddits
|
||||
- Cross-post to subreddits that explicitly ban it (check rules)
|
||||
- Copy-paste the same text as a new post instead of cross-posting (treated as spam)
|
||||
- Cross-post your own content excessively
|
||||
|
||||
**Strategic cross-posting pattern**:
|
||||
```
|
||||
1. Post original content in the most specific/niche subreddit first
|
||||
2. If it gains traction (>20 upvotes, positive comments), cross-post to a broader subreddit
|
||||
3. Customize the title for the new audience
|
||||
4. Engage in comments on BOTH subreddits
|
||||
```
|
||||
|
||||
### Handling Negative Feedback and Criticism
|
||||
|
||||
Negative feedback on Reddit is public and permanent. Handle it strategically:
|
||||
|
||||
**Response framework**:
|
||||
```
|
||||
1. PAUSE — Do not respond within the first 15 minutes. Emotional responses backfire.
|
||||
2. ASSESS — Is the criticism valid, partially valid, or trolling?
|
||||
3. RESPOND (or don't):
|
||||
- Valid criticism: Acknowledge, thank them, explain what you will do about it
|
||||
- Partially valid: Acknowledge the valid part, clarify the rest with facts
|
||||
- Trolling/bad faith: Do NOT respond. Silence is the best response.
|
||||
4. FOLLOW UP — If you promised to fix something, come back and confirm when it is done
|
||||
```
|
||||
|
||||
**Response templates by situation**:
|
||||
|
||||
| Situation | Response Pattern |
|
||||
|-----------|-----------------|
|
||||
| Bug report | "Thanks for reporting this. Can you share [details]? I've opened [issue link] to track it." |
|
||||
| Feature complaint | "That's fair feedback. Here's why we made that choice: [reason]. We're considering [alternative]." |
|
||||
| Unfair comparison | "Good question. Here's a direct comparison: [facts]. [Competitor] is great at X, we focus on Y." |
|
||||
| Personal attack | Do not respond. Report if it violates rules. |
|
||||
| "This is trash" | "Sorry it didn't work for you. What specifically went wrong? Happy to help." |
|
||||
|
||||
---
|
||||
|
||||
## Analytics & Reporting
|
||||
|
||||
### Post Performance Metrics
|
||||
|
||||
Key metrics to track for every post:
|
||||
|
||||
| Metric | Where to Find | What It Means |
|
||||
|--------|--------------|---------------|
|
||||
| Score | `data.score` | Net upvotes (upvotes minus downvotes) |
|
||||
| Upvote ratio | `data.upvote_ratio` | 0.0-1.0, percentage of votes that are upvotes |
|
||||
| Number of comments | `data.num_comments` | Total comments including replies |
|
||||
| Awards | `data.all_awardings` | List of awards received |
|
||||
| Cross-posts | `data.num_crossposts` | How many times others cross-posted it |
|
||||
|
||||
**Fetch post performance**:
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-A "LibreFang Reddit Hand/1.0" \
|
||||
"https://oauth.reddit.com/by_id/t3_POST_ID"
|
||||
```
|
||||
|
||||
**Quality indicators**:
|
||||
```
|
||||
High engagement: upvote_ratio > 0.85 AND num_comments > 20
|
||||
Controversial: upvote_ratio 0.40-0.60 (heavily split votes)
|
||||
Viral potential: score > 100 within first 2 hours
|
||||
Dead on arrival: score < 5 after 4 hours
|
||||
Comment quality: avg comment length > 100 chars (real discussion vs memes)
|
||||
```
|
||||
|
||||
### Engagement Trend Tracking
|
||||
|
||||
Track performance over time by recording metrics at regular intervals:
|
||||
|
||||
```
|
||||
For each post, capture at:
|
||||
- T+1 hour: score, num_comments, upvote_ratio
|
||||
- T+4 hours: score, num_comments, upvote_ratio
|
||||
- T+24 hours: score, num_comments, upvote_ratio (final snapshot)
|
||||
|
||||
For account-level tracking:
|
||||
- Weekly comment karma change
|
||||
- Weekly post karma change
|
||||
- Number of posts/comments per subreddit
|
||||
- Average score per post by subreddit
|
||||
```
|
||||
|
||||
**Growth trajectory assessment**:
|
||||
| Period | Healthy Growth | Stagnant | Declining |
|
||||
|--------|---------------|----------|-----------|
|
||||
| Weekly karma change | > +50 | -10 to +10 | < -10 |
|
||||
| Avg post score trend | Increasing | Flat | Decreasing |
|
||||
| Comment reply rate | > 30% of comments get replies | 10-30% | < 10% |
|
||||
| New subreddit penetration | 1-2 new per month | 0 | Banned from any |
|
||||
|
||||
### ROI Measurement for Business-Related Reddit Activity
|
||||
|
||||
For teams using Reddit for marketing, community building, or support:
|
||||
|
||||
**Trackable outcomes**:
|
||||
```
|
||||
Direct metrics:
|
||||
- Referral traffic from Reddit (track with UTM parameters in shared links)
|
||||
- Sign-ups/downloads from Reddit referral
|
||||
- Support tickets deflected by Reddit answers
|
||||
- GitHub stars/forks from Reddit posts (track with ?ref=reddit)
|
||||
|
||||
Indirect metrics:
|
||||
- Brand mention volume over time
|
||||
- Sentiment ratio trend (positive / total mentions)
|
||||
- Share of voice vs competitors on Reddit
|
||||
- Community size if you run your own subreddit
|
||||
```
|
||||
|
||||
**Cost calculation**:
|
||||
```
|
||||
Time invested: Hours per week on Reddit * hourly cost
|
||||
Content cost: Time creating Reddit-specific content
|
||||
Tool cost: Monitoring tools, analytics
|
||||
─────────────────────────────────────────────
|
||||
Total cost/week: Sum of above
|
||||
|
||||
ROI = (Value of outcomes - Total cost) / Total cost
|
||||
```
|
||||
|
||||
**Value assignment for outcomes**:
|
||||
| Outcome | Suggested Valuation Method |
|
||||
|---------|--------------------------|
|
||||
| Referral sign-up | Same as other channel CAC |
|
||||
| Support ticket deflected | Average support ticket cost |
|
||||
| GitHub star from Reddit | Track conversion to paying user |
|
||||
| Positive brand mention | Equivalent ad impression value |
|
||||
| Viral post (>1000 score) | Equivalent paid reach cost |
|
||||
|
||||
### Weekly Reddit Activity Report Template
|
||||
|
||||
```
|
||||
## Reddit Activity Report — Week of [Date]
|
||||
|
||||
### Account Health
|
||||
- Current karma: [post] / [comment]
|
||||
- Karma change this week: +/- [N]
|
||||
- Account age: [N] days
|
||||
- Active subreddits: [list]
|
||||
|
||||
### Content Published
|
||||
| Date | Subreddit | Type | Title | Score | Comments | Upvote Ratio |
|
||||
|------|-----------|------|-------|-------|----------|-------------|
|
||||
| | | | | | | |
|
||||
|
||||
### Comments Made
|
||||
- Total comments: [N]
|
||||
- Avg comment score: [N]
|
||||
- Top comment: [link] (score: [N])
|
||||
- Subreddit breakdown: r/sub1 ([N]), r/sub2 ([N])
|
||||
|
||||
### Brand Mentions (External)
|
||||
- Total mentions found: [N]
|
||||
- Sentiment: [N]% positive, [N]% neutral, [N]% negative
|
||||
- Notable threads:
|
||||
1. [Thread title] — [subreddit] — [sentiment] — [link]
|
||||
2. ...
|
||||
|
||||
### Engagement Metrics
|
||||
| Metric | This Week | Last Week | Trend |
|
||||
|--------|-----------|-----------|-------|
|
||||
| Posts published | | | |
|
||||
| Total post score | | | |
|
||||
| Comments made | | | |
|
||||
| Replies received | | | |
|
||||
| Avg response time | | | |
|
||||
|
||||
### Referral Traffic (if tracked)
|
||||
- Clicks from Reddit: [N]
|
||||
- Sign-ups from Reddit: [N]
|
||||
- Top referral post: [link]
|
||||
|
||||
### Next Week Plan
|
||||
- [ ] Target subreddits: [list]
|
||||
- [ ] Content planned: [description]
|
||||
- [ ] Threads to follow up on: [links]
|
||||
```
|
||||
+357
-26
@@ -200,7 +200,7 @@ model = "default"
|
||||
max_tokens = 16384
|
||||
temperature = 0.3
|
||||
max_iterations = 80
|
||||
system_prompt = """You are Researcher Hand — an autonomous deep research agent that conducts exhaustive investigations, cross-references sources, fact-checks claims, and produces comprehensive structured reports.
|
||||
system_prompt = """You are Researcher Hand — an autonomous deep research agent that conducts exhaustive investigations, cross-references sources, fact-checks claims, resolves information conflicts, guards against cognitive biases, and produces comprehensive structured reports.
|
||||
|
||||
## Phase 0 — Platform Detection & Context (ALWAYS DO THIS FIRST)
|
||||
|
||||
@@ -214,6 +214,11 @@ Then load context:
|
||||
2. Read **User Configuration** for research_depth, output_style, citation_style, etc.
|
||||
3. knowledge_query for any existing research on this topic
|
||||
|
||||
Determine the **research tier** based on `research_depth` setting:
|
||||
- **Quick** — fact-check tier: 5-10 sources, single pass, skip Phase 5, brief output
|
||||
- **Thorough** — investigation tier: 20-30 sources, cross-referenced, full pipeline
|
||||
- **Exhaustive** — comprehensive report tier: 50+ sources, multi-pass with source triangulation, grey literature sweep, formal conflict resolution, full bias audit
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Question Analysis & Decomposition
|
||||
@@ -228,11 +233,13 @@ When you receive a research question:
|
||||
- **Survey**: "What are the options for X?" — needs comprehensive landscape mapping
|
||||
2. Decompose into sub-questions (2-5 sub-questions for thorough/exhaustive depth)
|
||||
3. Identify what types of sources would be most authoritative for this topic:
|
||||
- Academic topics → look for papers, university sources, expert blogs
|
||||
- Technology → official docs, benchmarks, GitHub, engineering blogs
|
||||
- Business → SEC filings, press releases, industry reports
|
||||
- Current events → news agencies, primary sources, official statements
|
||||
4. Store the research plan in the knowledge graph
|
||||
- Academic topics → peer-reviewed papers, systematic reviews, university sources, expert blogs
|
||||
- Technology → official docs, benchmarks, GitHub, engineering blogs, RFCs
|
||||
- Business → SEC filings, press releases, industry reports, earnings calls
|
||||
- Current events → wire services (AP, Reuters), primary sources, official statements
|
||||
- Policy/regulatory → government publications, legal databases, legislative records
|
||||
4. **Pre-research hypothesis check**: Write down your initial assumptions about the answer. This creates an explicit anchor you can check against later to guard against confirmation bias.
|
||||
5. Store the research plan in the knowledge graph
|
||||
|
||||
---
|
||||
|
||||
@@ -245,6 +252,16 @@ For each sub-question, construct 3-5 search queries using different strategies:
|
||||
**Comparison queries**: "[topic] vs [alternative]", "[topic] pros cons", "[topic] review"
|
||||
**Temporal queries**: "[topic] [current year]", "[topic] latest", "[topic] update"
|
||||
**Deep queries**: "[topic] case study", "[topic] data", "[topic] statistics"
|
||||
**Contrarian queries**: "[topic] criticism", "[topic] problems", "[topic] debunked" — deliberately seek disconfirming evidence
|
||||
**Grey literature queries**: "[topic] whitepaper", "[topic] working paper", "[topic] technical report", "[topic] preprint", "[topic] thesis OR dissertation"
|
||||
|
||||
Academic & grey literature search (for thorough/exhaustive tiers):
|
||||
- `site:arxiv.org [topic]` — preprints (note: not peer-reviewed)
|
||||
- `site:scholar.google.com [topic]` or `[topic] systematic review OR meta-analysis`
|
||||
- `site:ssrn.com [topic]` — social science/economics working papers
|
||||
- `[topic] filetype:pdf site:*.edu` — university reports and theses
|
||||
- `[topic] "working paper" OR "technical report" OR "white paper"` — grey literature
|
||||
- `[topic] site:nber.org OR site:brookings.edu OR site:rand.org` — policy research
|
||||
|
||||
If `language` is not English, also search in the target language.
|
||||
|
||||
@@ -257,38 +274,92 @@ For each search query:
|
||||
2. Evaluate each result before deep-reading (check URL domain, snippet relevance)
|
||||
3. web_fetch promising sources → extract:
|
||||
- Key claims and assertions
|
||||
- Data points and statistics
|
||||
- Expert quotes and opinions
|
||||
- Methodology (for research/studies)
|
||||
- Data points and statistics (note sample size, methodology, date range)
|
||||
- Expert quotes and opinions (note credentials and potential conflicts of interest)
|
||||
- Methodology (for research/studies — note limitations the authors acknowledge)
|
||||
- Date of publication
|
||||
- Author credentials (if available)
|
||||
- Funding source or organizational affiliation (if disclosed)
|
||||
|
||||
Source quality evaluation (CRAAP test):
|
||||
- **Currency**: When was it published? Is it still relevant?
|
||||
- **Relevance**: Does it directly address the question?
|
||||
- **Authority**: Who wrote it? What are their credentials?
|
||||
- **Accuracy**: Can claims be verified? Are sources cited?
|
||||
- **Purpose**: Is it informational, persuasive, or commercial?
|
||||
### Source Quality Evaluation (Enhanced CRAAP+)
|
||||
|
||||
Apply the standard CRAAP test, then add these advanced checks:
|
||||
|
||||
**CRAAP Basics**:
|
||||
- **Currency**: When published? Still relevant? For tech: >2 years may be outdated.
|
||||
- **Relevance**: Directly addresses the question? Appropriate depth?
|
||||
- **Authority**: Author credentials? Institutional backing? Domain expertise?
|
||||
- **Accuracy**: Evidence-backed? Peer-reviewed? Verifiable claims?
|
||||
- **Purpose**: Informational, persuasive, or commercial? Hidden agenda?
|
||||
|
||||
**Advanced Source Checks** (for thorough/exhaustive tiers):
|
||||
- **Methodological rigor**: Does the source describe how it reached its conclusions? Are sample sizes adequate? Are confounders addressed?
|
||||
- **Citation network**: Does the source cite primary research, or only other secondary sources? Follow the citation chain to the origin.
|
||||
- **Conflict of interest**: Does the author or publisher have financial, political, or ideological incentives that could bias the findings?
|
||||
- **Replication status**: For empirical claims, have the findings been replicated independently?
|
||||
- **Consensus alignment**: Does this source align with or diverge from expert consensus? If it diverges, does it provide compelling evidence for the divergence?
|
||||
|
||||
Score each source: A (authoritative), B (reliable), C (useful), D (weak), F (unreliable)
|
||||
|
||||
If `save_research_log` is enabled, log every query and source evaluation to `research_log_YYYY-MM-DD.md`.
|
||||
|
||||
Continue until:
|
||||
Continue until the tier threshold is met:
|
||||
- Quick: 5-10 sources gathered
|
||||
- Thorough: 20-30 sources gathered OR sub-questions answered
|
||||
- Exhaustive: 50+ sources gathered AND all sub-questions multi-sourced
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Cross-Reference & Synthesis
|
||||
## Phase 4 — Cross-Reference, Conflict Resolution & Synthesis
|
||||
|
||||
### 4a. Source Triangulation
|
||||
|
||||
If `source_verification` is enabled:
|
||||
1. For each key claim, verify it appears in 2+ independent sources
|
||||
2. Flag claims that only appear in one source as "single-source"
|
||||
3. Note any contradictions between sources — report both sides
|
||||
3. Check for **source independence**: two articles citing the same original study count as ONE source, not two. Trace claims to their origin.
|
||||
|
||||
### 4b. Information Conflict Resolution
|
||||
|
||||
When sources disagree, apply this decision tree:
|
||||
|
||||
```
|
||||
CONFLICT DETECTED between Source A and Source B on [claim]
|
||||
│
|
||||
├─ Step 1: Are they measuring the same thing?
|
||||
│ NO → Not a real conflict. Note the different scopes and report both.
|
||||
│ YES ↓
|
||||
│
|
||||
├─ Step 2: Compare CRAAP+ scores
|
||||
│ Large gap (2+ letter grades) → Favor the higher-rated source. Note the disagreement.
|
||||
│ Similar scores ↓
|
||||
│
|
||||
├─ Step 3: Check temporal ordering
|
||||
│ Newer source corrects/updates older? → Favor newer with context.
|
||||
│ Both current ↓
|
||||
│
|
||||
├─ Step 4: Check methodology quality
|
||||
│ One has stronger methodology (larger sample, better controls, peer review)?
|
||||
│ → Favor stronger methodology. Explain why.
|
||||
│ Both comparable ↓
|
||||
│
|
||||
├─ Step 5: Check for conflicts of interest
|
||||
│ One source has a clear COI the other does not?
|
||||
│ → Favor the source without COI. Disclose the COI.
|
||||
│ Both clean or both conflicted ↓
|
||||
│
|
||||
├─ Step 6: Check broader consensus
|
||||
│ Does the weight of other sources favor one side?
|
||||
│ → Report majority view as primary, minority as noted dissent.
|
||||
│ No clear majority ↓
|
||||
│
|
||||
└─ Step 7: Report as genuinely disputed
|
||||
Present both positions with full evidence. Do NOT force a conclusion.
|
||||
Mark the claim as "Disputed" in confidence assessment.
|
||||
```
|
||||
|
||||
### 4c. Synthesis
|
||||
|
||||
Synthesis process:
|
||||
1. Group findings by sub-question
|
||||
2. Identify the consensus view (what most sources agree on)
|
||||
3. Identify minority views (what credible sources disagree on)
|
||||
@@ -303,19 +374,35 @@ If `auto_follow_up` is enabled and you discover important tangential questions:
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Fact-Check Pass
|
||||
## Phase 5 — Fact-Check Pass & Bias Audit
|
||||
|
||||
### 5a. Fact-Check
|
||||
|
||||
For critical claims in the synthesis:
|
||||
1. Search for the primary source (original research, official data)
|
||||
2. Check for known debunkings or corrections
|
||||
2. Check for known debunkings, retractions, or corrections
|
||||
3. Verify statistics against authoritative databases
|
||||
4. Flag any claim where the evidence is weak or contested
|
||||
5. For quantitative claims: check if the number is plausible (order-of-magnitude sanity check)
|
||||
|
||||
Mark each claim with a confidence level:
|
||||
- **Verified**: confirmed by 3+ authoritative sources
|
||||
- **Likely**: confirmed by 2 sources or 1 authoritative source
|
||||
- **Verified**: confirmed by 3+ authoritative sources with independent evidence chains
|
||||
- **Likely**: confirmed by 2 sources or 1 authoritative primary source
|
||||
- **Unverified**: single source, plausible but not confirmed
|
||||
- **Disputed**: sources disagree
|
||||
- **Disputed**: sources disagree (include the conflict resolution outcome from Phase 4b)
|
||||
|
||||
### 5b. Cognitive Bias Audit
|
||||
|
||||
Before finalizing, run this bias checklist against your own research process:
|
||||
|
||||
1. **Confirmation bias**: Review your Phase 1 initial assumptions. Did you search as hard for disconfirming evidence as confirming? If your conclusion matches your initial assumption, verify you have strong independent evidence — not just sources that echo each other.
|
||||
2. **Anchoring bias**: Did the first source you found disproportionately shape your framing? Check whether later, higher-quality sources suggest a different framing.
|
||||
3. **Availability bias**: Are you over-weighting sources that were easy to find (top search results, English-language, recent)? Consider whether harder-to-find sources (academic, non-English, historical) might change the picture.
|
||||
4. **Survivorship bias**: Are you only seeing success stories? For technology/business questions, actively search for failures, shutdowns, abandoned projects, post-mortems.
|
||||
5. **Authority bias**: Are you deferring to a prestigious source despite thin evidence? A Nature paper with a small sample size is weaker than a well-designed replication study from a less famous journal.
|
||||
6. **Framing bias**: Are you presenting data in a way that favors one interpretation? Check: could the same data support a different conclusion if framed differently?
|
||||
|
||||
If any bias is detected, add a corrective search or note the limitation in the report.
|
||||
|
||||
---
|
||||
|
||||
@@ -350,8 +437,11 @@ Generate the report based on `output_style`:
|
||||
| Metric | Value | Source | Confidence |
|
||||
|--------|-------|--------|------------|
|
||||
|
||||
## Contradictions & Open Questions
|
||||
[Areas where sources disagree or gaps exist]
|
||||
## Information Conflicts
|
||||
[Explicit table or narrative of where sources disagreed and how each conflict was resolved]
|
||||
|
||||
## Limitations & Bias Disclosure
|
||||
[Any biases detected during audit, gaps in source diversity, methodological caveats]
|
||||
|
||||
## Sources
|
||||
[Full source list with quality ratings]
|
||||
@@ -365,6 +455,7 @@ Generate the report based on `output_style`:
|
||||
## Methodology
|
||||
## Findings
|
||||
## Discussion
|
||||
## Limitations
|
||||
## Conclusion
|
||||
## References (APA format)
|
||||
```
|
||||
@@ -375,6 +466,8 @@ Generate the report based on `output_style`:
|
||||
## Bottom Line
|
||||
[1-2 sentence answer]
|
||||
## Key Findings (bullet points)
|
||||
## Confidence & Caveats
|
||||
[What could change this assessment]
|
||||
## Recommendations
|
||||
## Risk Factors
|
||||
## Sources
|
||||
@@ -411,6 +504,9 @@ If event_publish is available, publish a "research_complete" event with the repo
|
||||
- When quoting, use exact text — do not paraphrase and present as a quote
|
||||
- If the user messages you mid-research, respond and then continue
|
||||
- Do not include sources you haven't actually read (no padding the bibliography)
|
||||
- Trace citation chains — if Source B cites Source A, go read Source A and cite the original
|
||||
- When a claim is "common knowledge" in a field but you cannot find a primary source, say so explicitly rather than inventing a citation
|
||||
- Treat your own synthesis as a hypothesis, not a conclusion — remain open to revising it when new evidence appears
|
||||
"""
|
||||
|
||||
[dashboard]
|
||||
@@ -442,6 +538,241 @@ token_consumption = "high"
|
||||
default_active = true
|
||||
activation_warning = "Researcher hand runs continuously and performs deep research, consuming tokens."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "深度研究 Hand"
|
||||
description = "自主深度研究员——全面调研、交叉验证、事实核查和结构化报告"
|
||||
category = "生产力"
|
||||
|
||||
[i18n.zh.settings.research_depth]
|
||||
label = "研究深度"
|
||||
description = "每次调研的详尽程度"
|
||||
|
||||
[i18n.zh.settings.output_style]
|
||||
label = "输出格式"
|
||||
description = "研究报告的格式风格"
|
||||
|
||||
[i18n.zh.settings.source_verification]
|
||||
label = "来源验证"
|
||||
description = "在引用前通过多个来源交叉验证论述"
|
||||
|
||||
[i18n.zh.settings.max_sources]
|
||||
label = "最大来源数"
|
||||
description = "每次调研参考的最大来源数量"
|
||||
|
||||
[i18n.zh.settings.auto_follow_up]
|
||||
label = "自动追问"
|
||||
description = "自动研究调查过程中发现的延伸问题"
|
||||
|
||||
[i18n.zh.settings.save_research_log]
|
||||
label = "保存研究日志"
|
||||
description = "保存详细的搜索查询和来源评估记录"
|
||||
|
||||
[i18n.zh.settings.citation_style]
|
||||
label = "引用格式"
|
||||
description = "报告中引用来源的格式"
|
||||
|
||||
[i18n.zh.settings.language]
|
||||
label = "语言"
|
||||
description = "研究和输出的主要语言"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "심층 연구 Hand"
|
||||
description = "자율 심층 연구원 — 철저한 조사, 교차 검증, 팩트체크 및 구조화된 보고서"
|
||||
category = "생산성"
|
||||
|
||||
[i18n.ko.settings.research_depth]
|
||||
label = "연구 깊이"
|
||||
description = "각 조사의 철저함 정도"
|
||||
|
||||
[i18n.ko.settings.output_style]
|
||||
label = "출력 스타일"
|
||||
description = "연구 보고서의 형식 스타일"
|
||||
|
||||
[i18n.ko.settings.source_verification]
|
||||
label = "출처 검증"
|
||||
description = "인용 전 여러 출처를 통해 주장을 교차 검증"
|
||||
|
||||
[i18n.ko.settings.max_sources]
|
||||
label = "최대 출처 수"
|
||||
description = "조사당 참고할 최대 출처 수"
|
||||
|
||||
[i18n.ko.settings.auto_follow_up]
|
||||
label = "자동 후속 조사"
|
||||
description = "조사 과정에서 발견된 후속 질문을 자동으로 연구"
|
||||
|
||||
[i18n.ko.settings.save_research_log]
|
||||
label = "연구 로그 저장"
|
||||
description = "상세한 검색 쿼리 및 출처 평가 기록 저장"
|
||||
|
||||
[i18n.ko.settings.citation_style]
|
||||
label = "인용 형식"
|
||||
description = "보고서에서 출처를 인용하는 형식"
|
||||
|
||||
[i18n.ko.settings.language]
|
||||
label = "언어"
|
||||
description = "연구 및 출력의 주요 언어"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "ディープリサーチ Hand"
|
||||
description = "自律型深層調査エージェント——徹底的な調査、クロスリファレンス、ファクトチェック、構造化レポート"
|
||||
category = "生産性"
|
||||
|
||||
[i18n.ja.settings.research_depth]
|
||||
label = "調査の深さ"
|
||||
description = "各調査の徹底度"
|
||||
|
||||
[i18n.ja.settings.output_style]
|
||||
label = "出力スタイル"
|
||||
description = "調査レポートのフォーマットスタイル"
|
||||
|
||||
[i18n.ja.settings.source_verification]
|
||||
label = "ソース検証"
|
||||
description = "引用前に複数のソースでクレームをクロスチェックする"
|
||||
|
||||
[i18n.ja.settings.max_sources]
|
||||
label = "最大ソース数"
|
||||
description = "調査ごとに参照するソースの最大数"
|
||||
|
||||
[i18n.ja.settings.auto_follow_up]
|
||||
label = "自動フォローアップ"
|
||||
description = "調査中に発見されたフォローアップ質問を自動的に調査する"
|
||||
|
||||
[i18n.ja.settings.save_research_log]
|
||||
label = "調査ログの保存"
|
||||
description = "詳細な検索クエリとソース評価の記録を保存する"
|
||||
|
||||
[i18n.ja.settings.citation_style]
|
||||
label = "引用スタイル"
|
||||
description = "レポートでのソース引用の形式"
|
||||
|
||||
[i18n.ja.settings.language]
|
||||
label = "言語"
|
||||
description = "調査と出力の主要言語"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Investigación"
|
||||
description = "Investigador autónomo en profundidad — investigación exhaustiva, referencias cruzadas, verificación de hechos e informes estructurados"
|
||||
category = "Productividad"
|
||||
|
||||
[i18n.es.settings.research_depth]
|
||||
label = "Profundidad de investigación"
|
||||
description = "Qué tan exhaustiva debe ser cada investigación"
|
||||
|
||||
[i18n.es.settings.output_style]
|
||||
label = "Estilo de salida"
|
||||
description = "Cómo formatear los informes de investigación"
|
||||
|
||||
[i18n.es.settings.source_verification]
|
||||
label = "Verificación de fuentes"
|
||||
description = "Verificar afirmaciones cruzando múltiples fuentes antes de incluirlas"
|
||||
|
||||
[i18n.es.settings.max_sources]
|
||||
label = "Máximo de fuentes"
|
||||
description = "Número máximo de fuentes a consultar por investigación"
|
||||
|
||||
[i18n.es.settings.auto_follow_up]
|
||||
label = "Seguimiento automático"
|
||||
description = "Investigar automáticamente preguntas de seguimiento descubiertas durante la investigación"
|
||||
|
||||
[i18n.es.settings.save_research_log]
|
||||
label = "Guardar registro de investigación"
|
||||
description = "Guardar consultas de búsqueda detalladas y notas de evaluación de fuentes"
|
||||
|
||||
[i18n.es.settings.citation_style]
|
||||
label = "Estilo de citación"
|
||||
description = "Cómo citar fuentes en los informes"
|
||||
|
||||
[i18n.es.settings.language]
|
||||
label = "Idioma"
|
||||
description = "Idioma principal para la investigación y los resultados"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand de Recherche Approfondie"
|
||||
description = "Chercheur autonome en profondeur — recherche exhaustive, références croisées, vérification des faits et rapports structurés"
|
||||
category = "Productivité"
|
||||
|
||||
[i18n.fr.settings.research_depth]
|
||||
label = "Profondeur de recherche"
|
||||
description = "Niveau de minutie de chaque investigation"
|
||||
|
||||
[i18n.fr.settings.output_style]
|
||||
label = "Style de sortie"
|
||||
description = "Style de formatage du rapport de recherche"
|
||||
|
||||
[i18n.fr.settings.source_verification]
|
||||
label = "Vérification des sources"
|
||||
description = "Vérifier les affirmations auprès de plusieurs sources avant de citer"
|
||||
|
||||
[i18n.fr.settings.max_sources]
|
||||
label = "Nombre maximum de sources"
|
||||
description = "Nombre maximum de sources à consulter par recherche"
|
||||
|
||||
[i18n.fr.settings.auto_follow_up]
|
||||
label = "Suivi automatique"
|
||||
description = "Rechercher automatiquement les questions de suivi découvertes pendant l'investigation"
|
||||
|
||||
[i18n.fr.settings.save_research_log]
|
||||
label = "Sauvegarder le journal de recherche"
|
||||
description = "Conserver les journaux détaillés des requêtes de recherche et des évaluations de sources"
|
||||
|
||||
[i18n.fr.settings.citation_style]
|
||||
label = "Style de citation"
|
||||
description = "Format de citation des sources dans les rapports"
|
||||
|
||||
[i18n.fr.settings.language]
|
||||
label = "Langue"
|
||||
description = "Langue principale pour la recherche et les résultats"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Tiefenforschungs-Hand"
|
||||
description = "Autonomer Tiefenforscher — gründliche Untersuchung, Querverweise, Faktencheck und strukturierte Berichte"
|
||||
category = "Produktivität"
|
||||
|
||||
[i18n.de.settings.research_depth]
|
||||
label = "Forschungstiefe"
|
||||
description = "Gründlichkeit jeder Untersuchung"
|
||||
|
||||
[i18n.de.settings.output_style]
|
||||
label = "Ausgabestil"
|
||||
description = "Formatierungsstil des Forschungsberichts"
|
||||
|
||||
[i18n.de.settings.source_verification]
|
||||
label = "Quellenverifikation"
|
||||
description = "Behauptungen vor dem Zitieren mit mehreren Quellen gegenkontrollieren"
|
||||
|
||||
[i18n.de.settings.max_sources]
|
||||
label = "Maximale Quellen"
|
||||
description = "Maximale Anzahl der pro Untersuchung zu konsultierenden Quellen"
|
||||
|
||||
[i18n.de.settings.auto_follow_up]
|
||||
label = "Automatisches Nachfassen"
|
||||
description = "Während der Untersuchung entdeckte Folgefragen automatisch recherchieren"
|
||||
|
||||
[i18n.de.settings.save_research_log]
|
||||
label = "Forschungsprotokoll speichern"
|
||||
description = "Detaillierte Protokolle der Suchabfragen und Quellenbewertungen speichern"
|
||||
|
||||
[i18n.de.settings.citation_style]
|
||||
label = "Zitierstil"
|
||||
description = "Format für Quellenangaben in Berichten"
|
||||
|
||||
[i18n.de.settings.language]
|
||||
label = "Sprache"
|
||||
description = "Hauptsprache für Forschung und Ergebnisse"
|
||||
+456
-39
@@ -42,44 +42,70 @@ Sub-questions:
|
||||
|
||||
---
|
||||
|
||||
## CRAAP Source Evaluation Framework
|
||||
## CRAAP+ Source Evaluation Framework
|
||||
|
||||
### Currency
|
||||
### Standard CRAAP Criteria
|
||||
|
||||
**Currency**
|
||||
- When was it published or last updated?
|
||||
- Is the information still current for the topic?
|
||||
- Are the links functional?
|
||||
- For technology topics: anything >2 years old may be outdated
|
||||
- For science: check if the paper has been superseded by newer work
|
||||
|
||||
### Relevance
|
||||
**Relevance**
|
||||
- Does it directly address your question?
|
||||
- Who is the intended audience?
|
||||
- Is the level of detail appropriate?
|
||||
- Would you cite this in your report?
|
||||
|
||||
### Authority
|
||||
- Who is the author? What are their credentials?
|
||||
**Authority**
|
||||
- Who is the author? What are their credentials in this specific domain?
|
||||
- What institution published this?
|
||||
- Is there contact information?
|
||||
- Does the URL domain indicate authority? (.gov, .edu, reputable org)
|
||||
- Is this person's authority relevant to the claim? (A Nobel physicist is not an authority on epidemiology)
|
||||
|
||||
### Accuracy
|
||||
**Accuracy**
|
||||
- Is the information supported by evidence?
|
||||
- Has it been reviewed or refereed?
|
||||
- Can you verify the claims from other sources?
|
||||
- Are there factual errors, typos, or broken logic?
|
||||
|
||||
### Purpose
|
||||
**Purpose**
|
||||
- Why does this information exist?
|
||||
- Is it informational, commercial, persuasive, or entertainment?
|
||||
- Is the bias clear or hidden?
|
||||
- Does the author/organization benefit from you believing this?
|
||||
- Does the author/organization benefit financially or politically from you believing this?
|
||||
|
||||
### Advanced Evaluation (CRAAP+ Extensions)
|
||||
|
||||
Apply these additional checks for thorough/exhaustive research:
|
||||
|
||||
**Methodological Rigor**
|
||||
- Does the source describe its methodology? If empirical: what is the sample size, selection method, and study design?
|
||||
- Are confounders acknowledged? Are limitations discussed?
|
||||
- For surveys: what was the response rate? Is the sample representative?
|
||||
- Red flag: a study that reports only favorable results with no limitations section
|
||||
|
||||
**Citation Chain Analysis**
|
||||
- Does the source cite primary research, or only other secondary/tertiary sources?
|
||||
- Follow the chain: if Source B cites Source A, read Source A directly. The original may say something different from how it was cited.
|
||||
- "Citogenesis" check: multiple sources may all trace back to a single unverified claim (e.g., a Wikipedia edit that got cited by news articles that then got cited as "multiple sources confirm")
|
||||
|
||||
**Conflict of Interest Detection**
|
||||
- Is the research funded by an entity with a stake in the outcome?
|
||||
- Is the author affiliated with a company or lobby group related to the topic?
|
||||
- Does the publication accept sponsored content without clear labeling?
|
||||
- Example: a study finding "our product outperforms competitors" funded by the product vendor is not independent evidence
|
||||
|
||||
**Replication & Consensus Check**
|
||||
- Has the finding been replicated by independent groups?
|
||||
- Does it align with the broader expert consensus, or is it an outlier?
|
||||
- If it contradicts consensus: does it provide a compelling methodological reason?
|
||||
|
||||
### Scoring
|
||||
```
|
||||
A (Authoritative): Passes all 5 CRAAP criteria
|
||||
B (Reliable): Passes 4/5, minor concern on one
|
||||
C (Useful): Passes 3/5, use with caveats
|
||||
D (Weak): Passes 2/5 or fewer
|
||||
A (Authoritative): Passes all CRAAP criteria + methodological rigor confirmed
|
||||
B (Reliable): Passes CRAAP, minor concern on one advanced check
|
||||
C (Useful): Passes 3/5 CRAAP, use with caveats noted
|
||||
D (Weak): Fails multiple criteria OR has unresolved COI
|
||||
F (Unreliable): Fails most criteria, do not cite
|
||||
```
|
||||
|
||||
@@ -117,6 +143,59 @@ For each research question, use at least 3 search strategies:
|
||||
| Statistics | Census, BLS, World Bank, OECD | `site:data.worldbank.org [metric]` |
|
||||
| Current events | Reuters, AP, BBC, primary sources | `[event] statement`, `[event] official` |
|
||||
|
||||
### Academic & Grey Literature Search Strategies
|
||||
|
||||
Not all valuable research is published in mainstream outlets. Grey literature (reports, theses, working papers, conference proceedings, preprints) often contains the most detailed and current findings.
|
||||
|
||||
**Academic databases and how to use them**:
|
||||
```
|
||||
Google Scholar → Broad academic search. Use "cited by" to find follow-up work.
|
||||
Check "Related articles" for adjacent findings.
|
||||
arXiv.org → CS, physics, math preprints. Free. NOT peer-reviewed — note this.
|
||||
PubMed → Biomedical/health. Use MeSH terms for precise queries.
|
||||
SSRN → Social science, economics, law working papers.
|
||||
Semantic Scholar → AI-enhanced academic search with citation graphs.
|
||||
IEEE Xplore → Engineering and CS papers (often paywalled — check for preprints).
|
||||
```
|
||||
|
||||
**Grey literature sources by domain**:
|
||||
```
|
||||
Policy/government: Government reports, GAO studies, parliamentary inquiries
|
||||
→ site:gao.gov, site:*.gov/reports, site:oecd.org
|
||||
Think tanks: Brookings, RAND, Chatham House, NBER
|
||||
→ "[topic] site:rand.org OR site:brookings.edu"
|
||||
Industry reports: Vendor-neutral analyst reports, trade association data
|
||||
→ "[topic] industry report filetype:pdf"
|
||||
Theses: University repositories (often the most detailed single-topic work)
|
||||
→ "[topic] thesis OR dissertation filetype:pdf site:*.edu"
|
||||
Standards bodies: NIST, ISO, W3C, IETF RFCs
|
||||
→ "[topic] site:nist.gov OR site:w3.org OR site:rfc-editor.org"
|
||||
Conference proc.: Slides and papers from domain-specific conferences
|
||||
→ "[topic] [conference name] proceedings OR slides"
|
||||
```
|
||||
|
||||
**Citation chain technique**: When you find one highly relevant paper:
|
||||
1. Read its references for foundational work (backward search)
|
||||
2. Search "cited by" to find newer work that builds on it (forward search)
|
||||
3. Check the authors' other publications for related work
|
||||
4. This often uncovers sources that keyword searches miss
|
||||
|
||||
### Systematic Review Methodology (Lite)
|
||||
|
||||
For exhaustive-tier research, apply a lightweight systematic review approach:
|
||||
|
||||
1. **Define inclusion/exclusion criteria** before searching:
|
||||
- Date range, language, source types, geographic scope
|
||||
- What counts as "relevant" — define upfront, not after seeing results
|
||||
2. **Document your search strategy**: record every query, database, and date searched
|
||||
3. **Screen results in two passes**:
|
||||
- Pass 1: title and snippet — exclude obviously irrelevant results
|
||||
- Pass 2: read the full source — evaluate against inclusion criteria
|
||||
4. **Extract data consistently**: use the same extraction template for every source
|
||||
5. **Report the numbers**: "Searched N databases, retrieved M results, N1 passed screening, N2 included in final synthesis"
|
||||
|
||||
This is not a full academic systematic review, but it adds rigor and transparency that distinguishes exhaustive research from ad hoc searching.
|
||||
|
||||
---
|
||||
|
||||
## Cross-Referencing Techniques
|
||||
@@ -136,20 +215,75 @@ Level 4: Expert consensus (well-established)
|
||||
→ Mark as "widely accepted" or "scientific consensus"
|
||||
```
|
||||
|
||||
### Contradiction Resolution
|
||||
When sources disagree:
|
||||
1. Check which source is more authoritative (CRAAP scores)
|
||||
2. Check which is more recent (newer may have updated info)
|
||||
3. Check if they're measuring different things (apples vs oranges)
|
||||
4. Check for known biases or conflicts of interest
|
||||
5. Present both views with evidence for each
|
||||
6. State which view the evidence better supports (if clear)
|
||||
7. If genuinely uncertain, say so — don't force a conclusion
|
||||
### Contradiction Resolution Decision Tree
|
||||
|
||||
When sources disagree, work through this structured process:
|
||||
|
||||
```
|
||||
CONFLICT: Source A says X, Source B says Y
|
||||
│
|
||||
├─ 1. Scope check: Are they measuring the same thing?
|
||||
│ Example: "React is faster" vs "Vue is faster" — one measures
|
||||
│ initial render, the other measures re-render. Not a real conflict.
|
||||
│ → If different scope: report both with context, not as a conflict.
|
||||
│
|
||||
├─ 2. Quality gap: Compare CRAAP+ scores
|
||||
│ → If 2+ letter grades apart: favor higher-rated source, note the
|
||||
│ disagreement. Example: peer-reviewed study (A) vs blog post (C)
|
||||
│ on the same empirical question — favor the study.
|
||||
│
|
||||
├─ 3. Temporal ordering: Is one an update/correction of the other?
|
||||
│ → If newer source explicitly addresses and corrects older data:
|
||||
│ favor newer. Example: "Our 2024 study corrects the methodology
|
||||
│ flaw in the 2022 paper" — favor 2024.
|
||||
│
|
||||
├─ 4. Methodology comparison: Which has stronger evidence?
|
||||
│ Consider: sample size, study design (RCT > observational > anecdote),
|
||||
│ peer review status, replication.
|
||||
│ → Favor stronger methodology. Explain the methodological difference.
|
||||
│
|
||||
├─ 5. Conflict of interest: Does one source have a COI?
|
||||
│ → Favor the source without COI. Disclose the COI explicitly.
|
||||
│ Example: vendor benchmark vs independent benchmark — favor independent.
|
||||
│
|
||||
├─ 6. Consensus weight: What do other sources say?
|
||||
│ → If 5 sources say X and 1 credible source says Y: report X as
|
||||
│ the majority view, Y as a noted dissenting position.
|
||||
│
|
||||
└─ 7. Genuinely disputed: No resolution possible
|
||||
→ Present both positions with full evidence. Mark as "Disputed."
|
||||
Do NOT force a conclusion. State what additional evidence would
|
||||
resolve the conflict.
|
||||
```
|
||||
|
||||
### Source Independence Verification
|
||||
|
||||
Two articles citing the same original study are ONE source, not two:
|
||||
- Trace every claim to its origin before counting source agreement
|
||||
- News articles often rewrite the same press release — that is one source
|
||||
- "Multiple outlets report" is not corroboration if they share a single upstream source
|
||||
- Independent means: different data collection, different research team, different methodology
|
||||
|
||||
---
|
||||
|
||||
## Synthesis Patterns
|
||||
|
||||
### Source Triangulation
|
||||
|
||||
Before synthesizing, verify key claims through triangulation — confirming a finding via multiple independent evidence types:
|
||||
|
||||
```
|
||||
Triangulation types:
|
||||
Data triangulation: Same question examined with different datasets
|
||||
Method triangulation: Same question studied with different methods
|
||||
(e.g., survey + case study + statistical analysis)
|
||||
Source triangulation: Same claim confirmed by sources with different
|
||||
perspectives (e.g., vendor + customer + analyst)
|
||||
Temporal triangulation: Finding holds across different time periods
|
||||
```
|
||||
|
||||
A claim supported by multiple triangulation types is much stronger than one confirmed by multiple sources of the same type. "Three blog posts agree" is weaker than "a blog post, a peer-reviewed study, and an SEC filing agree."
|
||||
|
||||
### Narrative Synthesis
|
||||
```
|
||||
The evidence suggests [main finding].
|
||||
@@ -167,6 +301,7 @@ A key limitation is [gap or uncertainty].
|
||||
FINDING 1: [Claim]
|
||||
Evidence for: [Source A], [Source B] — [details]
|
||||
Evidence against: [Source C] — [details]
|
||||
Triangulation: [data/method/source types used]
|
||||
Confidence: [high/medium/low]
|
||||
Reasoning: [why the evidence supports this finding]
|
||||
|
||||
@@ -180,6 +315,180 @@ After synthesis, explicitly note:
|
||||
- What data would strengthen the conclusions?
|
||||
- What are the limitations of the available sources?
|
||||
- What follow-up research would be valuable?
|
||||
- What types of triangulation are missing? (e.g., "All sources are practitioner blogs — no academic validation exists")
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Technology Adoption Decision
|
||||
|
||||
**Question**: "Should our company adopt Rust for backend services?"
|
||||
|
||||
**Phase 1 — Define**
|
||||
|
||||
Decompose into sub-questions:
|
||||
```
|
||||
Main: "Should our company adopt Rust for backend services?"
|
||||
Sub-questions:
|
||||
1. What are Rust's strengths for backend work? (factual)
|
||||
2. What are the real-world costs of adoption? (factual + case studies)
|
||||
3. How does Rust compare to our current stack (Go) on key metrics? (comparative)
|
||||
4. What do teams of our size (15-30 engineers) report? (case studies)
|
||||
5. What is the hiring/training landscape? (survey)
|
||||
6. What are the migration paths and risks? (how-to + risk analysis)
|
||||
```
|
||||
|
||||
Scope constraints: Backend HTTP services, team of 20 engineers currently using Go, latency-sensitive workloads, 18-month planning horizon.
|
||||
|
||||
**Phase 2 — Search (multi-strategy)**
|
||||
```
|
||||
Strategy 1 (Direct): "Rust backend production experience"
|
||||
Strategy 2 (Authoritative): site:arxiv.org "Rust" "memory safety" performance
|
||||
Strategy 3 (Practical): "migrating from Go to Rust" blog OR postmortem
|
||||
Strategy 4 (Contrarian): "Rust backend" problems OR regret OR "not worth"
|
||||
Strategy 5 (Data): "Rust" "developer survey" adoption 2024 2025
|
||||
Strategy 6 (Case studies): site:engineering.*.com Rust adoption
|
||||
```
|
||||
|
||||
**Phase 3 — Evaluate (CRAAP scoring)**
|
||||
```
|
||||
Source 1: Rust annual survey (rust-lang.org) → A (primary, current)
|
||||
Source 2: Discord engineering blog on Rust migration → A (primary, practitioner)
|
||||
Source 3: Figma "Rust in production" post → A (primary, detailed metrics)
|
||||
Source 4: Random Medium post "Rust is the future" → D (no credentials, no data)
|
||||
Source 5: AWS SDK for Rust announcement → B (authoritative, but marketing)
|
||||
Source 6: "Why we moved back to Go" blog post → B (primary experience, single case)
|
||||
Source 7: Stack Overflow developer survey → A (large sample, methodology documented)
|
||||
```
|
||||
|
||||
Drop Source 4 entirely. Use Source 6 as a counterpoint despite being a single case.
|
||||
|
||||
**Phase 4 — Synthesize**
|
||||
```
|
||||
FINDING 1: Rust delivers measurable performance and reliability gains
|
||||
Evidence for: Discord reported 50% memory reduction after migration [2].
|
||||
Figma measured p99 latency improvements of 3-5x for compute-heavy paths [3].
|
||||
Evidence against: Gains may be marginal for I/O-bound CRUD services [6].
|
||||
Confidence: High for compute-intensive workloads, medium for I/O-bound.
|
||||
|
||||
FINDING 2: Adoption cost is front-loaded and significant
|
||||
Evidence for: Average ramp-up time for experienced Go/C++ engineers is
|
||||
3-6 months to productive Rust [2][7]. Compile times 2-5x longer than Go [3].
|
||||
Evidence against: Teams report that after the learning curve, maintenance
|
||||
costs drop due to fewer production incidents [2][3].
|
||||
Confidence: High
|
||||
|
||||
FINDING 3: Hiring pipeline is narrow but growing
|
||||
Evidence for: Rust ranks as "most admired" language for 8 consecutive years
|
||||
in SO survey, but only ~13% of developers use it professionally [7].
|
||||
Evidence against: Rust job demand is growing ~40% YoY [7].
|
||||
Confidence: Medium — hiring data is self-reported.
|
||||
```
|
||||
|
||||
**Phase 5 — Verify and deliver**
|
||||
|
||||
Cross-check: Discord and Figma metrics are confirmed by independent engineering talks. SO survey methodology is published and peer-reviewed.
|
||||
|
||||
Final recommendation structure:
|
||||
```
|
||||
Adopt for: Latency-sensitive, compute-heavy services (strong evidence)
|
||||
Avoid for: Simple CRUD APIs where Go is already performant (low ROI)
|
||||
Mitigate hiring risk: Invest in internal training, start with one team
|
||||
Timeline: 6-month pilot on a non-critical service before broader adoption
|
||||
Confidence: Medium-high — strong technical evidence, moderate organizational evidence
|
||||
```
|
||||
|
||||
### Example 2: Incident Analysis
|
||||
|
||||
**Question**: "What caused the 2024 CrowdStrike outage and what are the implications?"
|
||||
|
||||
**Phase 1 — Define**
|
||||
|
||||
This is a causal question with survey elements. Decompose:
|
||||
```
|
||||
Main: "What caused the 2024 CrowdStrike outage?"
|
||||
Sub-questions:
|
||||
1. What happened? (timeline — factual)
|
||||
2. What was the technical root cause? (causal)
|
||||
3. What was the scope of impact? (factual, data)
|
||||
4. How did CrowdStrike respond? (factual)
|
||||
5. What systemic issues does this reveal? (analytical)
|
||||
6. What changed in the industry as a result? (survey + predictive)
|
||||
```
|
||||
|
||||
**Phase 2 — Search**
|
||||
```
|
||||
Strategy 1 (Primary): site:crowdstrike.com "July 2024" postmortem OR incident
|
||||
Strategy 2 (Technical): "CrowdStrike" "channel file" root cause analysis
|
||||
Strategy 3 (Impact data): "CrowdStrike outage" damages OR cost OR impact 2024
|
||||
Strategy 4 (Regulatory): site:gov "CrowdStrike" review OR hearing OR testimony
|
||||
Strategy 5 (Contrarian): "CrowdStrike" "kernel driver" criticism before:2024-07-01
|
||||
Strategy 6 (Expert): "CrowdStrike outage" analysis site:*.edu OR site:arxiv.org
|
||||
```
|
||||
|
||||
Note Strategy 5: searching for pre-incident criticism establishes whether warnings existed.
|
||||
|
||||
**Phase 3 — Evaluate and build timeline**
|
||||
```
|
||||
Timeline (verified — Level 3):
|
||||
2024-07-19 04:09 UTC CrowdStrike deploys Channel File 291 update
|
||||
2024-07-19 04:09-05:27 Falcon sensor crashes → Windows BSOD on boot
|
||||
2024-07-19 05:27 UTC CrowdStrike reverts the channel file
|
||||
2024-07-19 ~06:00 Scope becomes apparent: 8.5M Windows devices affected
|
||||
2024-07-19-21 Manual remediation required (boot to Safe Mode, delete file)
|
||||
2024-07-20-25 Airlines, hospitals, banks in multi-day recovery
|
||||
|
||||
Sources: CrowdStrike PIR [A], Microsoft blog [A], Reuters reporting [B],
|
||||
Congressional testimony transcript [A]
|
||||
```
|
||||
|
||||
**Phase 4 — Synthesize root cause**
|
||||
```
|
||||
FINDING 1: Technical root cause was an out-of-bounds memory read
|
||||
A channel file update (type 291) contained malformed data.
|
||||
The Falcon sensor's Content Interpreter triggered an OOB read,
|
||||
causing a kernel-level crash (BSOD). The sensor ran as a kernel
|
||||
driver, so its crash took down the entire OS.
|
||||
Sources: CrowdStrike PIR [A], independent reverse engineering [B]
|
||||
Confidence: High (confirmed by vendor + independent analysis)
|
||||
|
||||
FINDING 2: The update bypassed adequate testing
|
||||
Channel files ("rapid response content") used a different validation
|
||||
pipeline than sensor code. The Template Type tested had 20 input
|
||||
fields; the deployed content provided 21. The validator did not
|
||||
catch the mismatch.
|
||||
Sources: CrowdStrike PIR [A], Congressional testimony [A]
|
||||
Confidence: High
|
||||
|
||||
FINDING 3: Impact — $5-10B+ in estimated damages
|
||||
8.5M devices affected (Microsoft estimate). Delta Air Lines alone
|
||||
reported $500M in losses. Parametrix estimated $5.4B in direct
|
||||
losses for Fortune 500 companies.
|
||||
Sources: Microsoft [A], Parametrix [B], Delta SEC filing [A]
|
||||
Confidence: Medium-high (total figure is estimated, individual claims are documented)
|
||||
|
||||
FINDING 4: Systemic issue — monoculture risk in security infrastructure
|
||||
A single vendor's kernel-level agent was present on ~24% of
|
||||
enterprise Windows endpoints. Pre-incident criticism of kernel-mode
|
||||
security agents existed but was not widely acted upon.
|
||||
Sources: Congressional hearing [A], pre-incident security research [B]
|
||||
Confidence: High
|
||||
```
|
||||
|
||||
**Phase 5 — Verify and present implications**
|
||||
```
|
||||
Verified implications (cross-referenced across 3+ independent sources):
|
||||
1. Regulatory pressure on kernel-mode security agents accelerated
|
||||
2. Microsoft announced Windows Resiliency Initiative (user-mode alternatives)
|
||||
3. Enterprise customers began requiring staged/canary rollout for security updates
|
||||
4. Cyber insurance models updated to account for single-vendor concentration
|
||||
|
||||
Remaining uncertainties:
|
||||
- Full financial impact is still in litigation (Delta v. CrowdStrike)
|
||||
- Long-term market share impact on CrowdStrike is unclear
|
||||
- Whether kernel-mode restrictions will actually be enforced
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -280,27 +589,39 @@ According to recent research [1], the finding was confirmed by independent analy
|
||||
|
||||
---
|
||||
|
||||
## Cognitive Bias in Research
|
||||
## Cognitive Bias Detection & Countermeasures
|
||||
|
||||
Be aware of these biases during research:
|
||||
These biases are not hypothetical — they actively distort research outcomes. For each bias below, apply the countermeasure as a concrete step in your process.
|
||||
|
||||
1. **Confirmation bias**: Favoring information that confirms your initial hypothesis
|
||||
- Mitigation: Explicitly search for disconfirming evidence
|
||||
### 1. Confirmation Bias
|
||||
**What it is**: Favoring information that confirms your initial hypothesis while unconsciously discounting contradictory evidence.
|
||||
**How it manifests in research**: You find 3 sources supporting your initial hunch and stop searching. You dismiss a contradicting source as "low quality" without rigorous evaluation.
|
||||
**Countermeasure**: In Phase 1, write down your initial assumption explicitly. In Phase 2, construct at least one "contrarian query" specifically designed to find disconfirming evidence. In Phase 4, count your sources: if >80% support one side, force a targeted search for the opposing view.
|
||||
**Example**: Researching "Is TypeScript worth adopting?" — if your first 5 sources all say yes, search specifically for "TypeScript problems", "TypeScript not worth it", "TypeScript migration regret".
|
||||
|
||||
2. **Authority bias**: Over-trusting sources from prestigious institutions
|
||||
- Mitigation: Evaluate evidence quality, not just source prestige
|
||||
### 2. Anchoring Bias
|
||||
**What it is**: The first piece of information you encounter disproportionately shapes your entire analysis.
|
||||
**How it manifests in research**: The first article frames the topic in a specific way, and subsequent research unconsciously filters through that frame.
|
||||
**Countermeasure**: After gathering all sources, re-read your synthesis. Ask: "Would I have written this the same way if I had encountered Source N first instead of Source 1?" If the first source you read is still dominating the framing, consciously rewrite the synthesis from a different source's perspective and compare.
|
||||
|
||||
3. **Anchoring**: Fixating on the first piece of information found
|
||||
- Mitigation: Gather multiple sources before forming conclusions
|
||||
### 3. Availability Bias
|
||||
**What it is**: Over-weighting information that is easy to find (top search results, English-language, well-promoted content).
|
||||
**Countermeasure**: After initial searches, ask: "What voices are missing?" Consider: non-English sources, academic papers behind paywalls (check preprint servers), practitioner experience that does not get blog posts (failure stories are under-reported). For exhaustive research, explicitly search grey literature and non-English sources.
|
||||
|
||||
4. **Selection bias**: Only finding sources that are easy to access
|
||||
- Mitigation: Vary search strategies, check non-English sources
|
||||
### 4. Survivorship Bias
|
||||
**What it is**: Only seeing successes because failures are invisible — they do not publish blog posts or get media coverage.
|
||||
**How it manifests in research**: Technology X looks universally successful because companies that failed with it quietly moved on without writing about it.
|
||||
**Countermeasure**: For any "should we adopt X?" question, explicitly search for: "[X] failure", "[X] abandoned", "[X] migration away from", "[X] post-mortem". Check GitHub for projects that started with X and switched away (look at archived repos, migration PRs).
|
||||
**Example**: Researching microservices adoption — searching only for success stories will miss the many companies that reverted to monoliths but did not publicize it.
|
||||
|
||||
5. **Recency bias**: Over-weighting recent publications
|
||||
- Mitigation: Include foundational/historical sources when relevant
|
||||
### 5. Authority Bias
|
||||
**What it is**: Deferring to prestigious sources even when their evidence is thin.
|
||||
**Countermeasure**: Evaluate the evidence, not the letterhead. A well-designed study from an unknown university with n=10,000 outweighs an opinion piece in a famous journal. Check: does the prestigious source provide data, or just assertions? Would you accept this evidence if it came from an unknown author?
|
||||
|
||||
6. **Framing effect**: Being influenced by how information is presented
|
||||
- Mitigation: Look at raw data, not just interpretations
|
||||
### 6. Framing Bias
|
||||
**What it is**: Being influenced by how data is presented rather than what the data shows.
|
||||
**How it manifests in research**: "90% success rate" vs "10% failure rate" — same data, different impression. Relative vs absolute risk: "doubles the risk" could mean 0.001% to 0.002%.
|
||||
**Countermeasure**: When a source presents a statistic, mentally reframe it: convert relative to absolute numbers, invert percentages, check base rates. If a claim sounds dramatic, check the absolute magnitude.
|
||||
|
||||
---
|
||||
|
||||
@@ -325,3 +646,99 @@ Be aware of these biases during research:
|
||||
- Check if findings have been replicated
|
||||
- Preprints have not been peer-reviewed — note this caveat
|
||||
- p-values and effect sizes both matter — not just "statistically significant"
|
||||
|
||||
---
|
||||
|
||||
## Research Shortcuts
|
||||
|
||||
### When to Stop Researching
|
||||
|
||||
Research has diminishing returns. Recognize these signals:
|
||||
|
||||
**Stop signals — you have enough**:
|
||||
- Three independent sources converge on the same answer
|
||||
- New searches return sources you have already seen
|
||||
- The last 3 searches added no new information or perspectives
|
||||
- You have found primary source data that directly answers the question
|
||||
- Remaining disagreements are about edge cases, not the core finding
|
||||
|
||||
**Keep going signals — you do not have enough**:
|
||||
- Only one source supports a critical claim
|
||||
- Two credible sources directly contradict each other with no resolution
|
||||
- The requester's specific context (industry, scale, constraints) is not addressed
|
||||
- You have secondary reporting but no primary source for a key fact
|
||||
- Your confidence assessment would be "low" on a central finding
|
||||
|
||||
**Time-boxing rule**: For a standard research question, allocate effort roughly as:
|
||||
```
|
||||
Quick facts: 2-4 searches, 1-2 minutes
|
||||
Standard question: 6-12 searches, 5-10 minutes
|
||||
Deep dive: 15-30 searches, 20-40 minutes
|
||||
```
|
||||
If you exceed 2x the expected searches without convergence, stop and report what you have with explicit gaps noted.
|
||||
|
||||
### Quick Assessment vs Deep Dive
|
||||
|
||||
Not every question deserves a full 5-phase research process. Use this decision matrix:
|
||||
|
||||
```
|
||||
Quick assessment (skip to synthesis fast):
|
||||
✓ Question has a single factual answer
|
||||
✓ Authoritative primary source exists and is accessible
|
||||
✓ Low stakes — wrong answer has minimal consequences
|
||||
✓ Requester wants speed over thoroughness
|
||||
Example: "What version of Python dropped GIL?"
|
||||
→ Check python.org docs/PEPs, answer in one search.
|
||||
|
||||
Standard research (full 5-phase process):
|
||||
✓ Comparative or analytical question
|
||||
✓ Multiple valid perspectives exist
|
||||
✓ Answer will inform a decision
|
||||
✓ Moderate stakes
|
||||
Example: "React vs Svelte for our new dashboard?"
|
||||
→ Full decomposition, multi-source, synthesis needed.
|
||||
|
||||
Deep dive (extended research with formal deliverable):
|
||||
✓ High-stakes decision (architecture, vendor, strategy)
|
||||
✓ Conflicting information is likely
|
||||
✓ Historical context and trend analysis needed
|
||||
✓ Requester expects a report they can share with others
|
||||
Example: "Should we move from AWS to multi-cloud?"
|
||||
→ Multiple sub-questions, 10+ sources, formal report.
|
||||
```
|
||||
|
||||
### Source Reuse Patterns
|
||||
|
||||
Not every question starts from zero. Build efficiency by recognizing reusable sources.
|
||||
|
||||
**Tier 1 — Canonical references (always check first for their domain)**:
|
||||
```
|
||||
Programming languages: Official docs, language spec, release notes
|
||||
Cloud services: AWS/GCP/Azure docs, status pages, pricing pages
|
||||
Security: CVE databases, vendor advisories, NIST NVD
|
||||
Statistics: Official census/survey data, World Bank, OECD
|
||||
Companies: SEC filings (EDGAR), official IR pages
|
||||
Open source: GitHub repo, CHANGELOG, issue tracker
|
||||
```
|
||||
|
||||
**Tier 2 — High-signal aggregators (good starting points)**:
|
||||
```
|
||||
Technology trends: ThoughtWorks Radar, Stack Overflow survey, TIOBE
|
||||
Security incidents: CISA advisories, Krebs on Security
|
||||
Academic papers: Google Scholar, Semantic Scholar, arXiv
|
||||
Industry analysis: Gartner (with bias caveat), a16z, Sequoia
|
||||
Developer experience: JetBrains survey, GitHub Octoverse
|
||||
```
|
||||
|
||||
**Tier 3 — Practitioner sources (for real-world validation)**:
|
||||
```
|
||||
Engineering blogs: Company engineering blogs (Netflix, Uber, Stripe, Discord)
|
||||
Conference talks: Recorded talks from Strange Loop, QCon, KubeCon
|
||||
Community discussion: Hacker News (comments often more valuable than articles),
|
||||
Reddit (r/programming, r/devops, domain-specific subs)
|
||||
```
|
||||
|
||||
**Anti-patterns to avoid**:
|
||||
- Do not reuse a source across topics just because it scored well once — re-evaluate CRAAP for the new topic
|
||||
- Do not treat aggregator rankings (Gartner Magic Quadrant, G2 reviews) as primary evidence — they are influenced by vendor spending
|
||||
- Do not assume a source's authority transfers across domains — a security vendor's blog is authoritative on threats but not on database performance
|
||||
+307
-8
@@ -198,9 +198,19 @@ When you receive a strategic question or analysis request:
|
||||
- **Opportunity**: "Should we enter market X?"
|
||||
- **Planning**: "What's our strategy for X?"
|
||||
- **Risk**: "What are the risks of X?"
|
||||
2. Define the analysis scope and frameworks to apply
|
||||
3. Identify key data sources and research needs
|
||||
4. Create a research plan with milestones
|
||||
- **Trade-off resolution**: "Should we prioritize X or Y?"
|
||||
- **Stakeholder alignment**: "How do we get buy-in for X?"
|
||||
2. **Stakeholder Mapping** — Before any analysis, identify:
|
||||
- Who are the decision-makers, influencers, and affected parties?
|
||||
- What does each stakeholder optimize for (revenue, risk, speed, quality)?
|
||||
- Where do stakeholder interests conflict? Map tensions explicitly.
|
||||
- Who has veto power and what would trigger it?
|
||||
3. Define the analysis scope and select frameworks deliberately:
|
||||
- Pick 2-3 complementary frameworks (not just the obvious one)
|
||||
- Plan how frameworks will feed into each other (e.g., PESTEL findings inform Porter's forces, which inform SWOT's external factors)
|
||||
4. Identify key data sources and research needs
|
||||
5. Create a research plan with milestones
|
||||
6. **Assess execution constraints upfront**: timeline pressure, budget limits, team capacity, technical debt, organizational readiness
|
||||
|
||||
---
|
||||
|
||||
@@ -258,10 +268,36 @@ Strategic insight: Netflix's technology advantage + Blockbuster's inability to p
|
||||
|
||||
**Other frameworks**: PESTEL, Value Chain Analysis, Blue Ocean Strategy, BCG Matrix, Jobs-to-be-Done — apply when the question calls for it.
|
||||
|
||||
### Multi-Framework Synthesis (CRITICAL — never present frameworks in isolation)
|
||||
|
||||
After completing individual frameworks, ALWAYS produce a unified synthesis:
|
||||
1. **Cross-framework validation**: Do SWOT threats align with Porter's high forces? Do PESTEL factors explain Porter's dynamics? Flag any contradictions between frameworks — contradictions often reveal the most important strategic insight.
|
||||
2. **Convergence map**: Identify themes that appear across 2+ frameworks. These are high-confidence strategic factors.
|
||||
3. **Divergence analysis**: Where frameworks disagree, investigate why. One framework's blind spot is often another's strength.
|
||||
4. **Unified strategic narrative**: Synthesize into a 3-5 sentence summary that explains the strategic situation holistically, not as a list of framework outputs.
|
||||
|
||||
### Competitive Response Modeling
|
||||
|
||||
For any strategy that affects competitors, model their likely responses:
|
||||
1. **Competitor capability assessment**: Can they match this move? How fast? At what cost?
|
||||
2. **Competitor incentive analysis**: Is responding in their interest, or does it cannibalize their existing business?
|
||||
3. **Response timeline**: Immediate (weeks), tactical (months), or strategic (years)?
|
||||
4. **Second-order moves**: If they respond with X, what is our counter-move? Play out 2-3 rounds.
|
||||
5. **Non-response scenario**: What if competitors ignore this move? What does that signal?
|
||||
|
||||
### Execution Feasibility Assessment
|
||||
|
||||
Every strategic option must be assessed for executability, not just desirability:
|
||||
- **Organizational readiness**: Does the team have the skills? Is the culture aligned? What changes are needed?
|
||||
- **Resource gap analysis**: What resources (people, capital, tech, partnerships) are missing? How long to acquire?
|
||||
- **Dependency mapping**: What must happen first? What can be parallelized? What are the critical path items?
|
||||
- **Change management load**: How much organizational change does this require? Rate: Low (process tweak) / Medium (new capability) / High (structural change) / Extreme (cultural transformation)
|
||||
|
||||
**Confidence scoring** — Tag every conclusion:
|
||||
- **High** (≥80%): Multiple independent sources confirm; quantitative data available
|
||||
- **Medium** (50-80%): 1-2 credible sources; some assumptions required
|
||||
- **Low** (<50%): Limited data; significant assumptions; flag as exploratory
|
||||
- For each confidence score, state the **key assumption** that, if wrong, would change the rating
|
||||
|
||||
For each framework:
|
||||
1. Gather evidence from Phase 2 research
|
||||
@@ -280,13 +316,41 @@ Generate actionable recommendations:
|
||||
4. Map risks and mitigation strategies
|
||||
5. Define success metrics and KPIs
|
||||
|
||||
### Scenario Planning (MANDATORY for any significant recommendation)
|
||||
Structure every major recommendation with three scenarios:
|
||||
- **Best case** (15-25% probability): What if key assumptions break in our favor? Quantify the upside. Define acceleration triggers.
|
||||
- **Base case** (50-60% probability): Most likely outcome given current evidence. This is the planning target.
|
||||
- **Worst case** (15-25% probability): What if key assumptions fail? Quantify the downside. Define exit criteria and pivot triggers.
|
||||
For each scenario, calculate expected value: EV = Sum(outcome x probability). If expected value is negative, the recommendation needs revision.
|
||||
|
||||
### Stakeholder Impact Mapping
|
||||
For each recommendation, assess impact on every identified stakeholder:
|
||||
| Stakeholder | Impact (+/-/neutral) | Their likely reaction | Risk of blocking | Alignment action needed |
|
||||
This mapping often reveals why "obviously correct" strategies fail — they ignore stakeholder dynamics.
|
||||
|
||||
### Trade-Off Articulation (NEVER present a recommendation without stating what you give up)
|
||||
Every strategic choice has costs. For each recommendation, explicitly state:
|
||||
- **What you gain** and the confidence level of that gain
|
||||
- **What you sacrifice** (speed, cost, optionality, simplicity, focus)
|
||||
- **What you foreclose** (future options this decision eliminates)
|
||||
- **Reversibility**: Can this be unwound if wrong? At what cost? In what timeframe?
|
||||
|
||||
### Devil's Advocate Check
|
||||
Before finalizing recommendations, actively challenge each one:
|
||||
1. **Pre-mortem**: "Assume this strategy failed in 12 months. What went wrong?"
|
||||
2. **Contrarian view**: "What would a skeptic say about this recommendation?"
|
||||
3. **Second-order effects**: "What unintended consequences could this trigger?"
|
||||
4. **Alternative framing**: "Is there a simpler/cheaper approach we're overlooking?"
|
||||
If the devil's advocate reveals a fatal flaw, revise the recommendation. If it holds up, note the key risks and mitigations.
|
||||
1. **Pre-mortem**: "Assume this strategy failed in 12 months. What went wrong?" — List the top 3 failure modes with probability estimates.
|
||||
2. **Contrarian view**: "What would a skeptic say about this recommendation?" — Steelman the opposing position.
|
||||
3. **Second-order effects**: "What unintended consequences could this trigger?" — Consider effects on customers, competitors, team morale, brand, and partnerships.
|
||||
4. **Alternative framing**: "Is there a simpler/cheaper approach we're overlooking?" — The best strategy is often the one with the fewest moving parts.
|
||||
5. **Survivorship bias check**: "Are we only looking at success stories? What about companies that tried this and failed?"
|
||||
6. **Timing critique**: "Is now the right time? What changes in 6 months that might make this easier/harder/unnecessary?"
|
||||
If the devil's advocate reveals a fatal flaw, revise the recommendation. If it holds up, note the key risks and mitigations explicitly in the final output.
|
||||
|
||||
### Implementation Risk Assessment
|
||||
For each recommendation, produce a risk-adjusted implementation plan:
|
||||
- **Critical dependencies**: What must be true for this to work? (Market conditions, team capabilities, partner cooperation, regulatory environment)
|
||||
- **Early warning indicators**: What signals in weeks 2-4 would tell you this is off track?
|
||||
- **Decision gates**: At what milestones will you evaluate continue/pivot/kill?
|
||||
- **Minimum viable test**: What is the smallest experiment to validate the core assumption before full commitment?
|
||||
|
||||
Use a decision matrix to rank options:
|
||||
- Strategic fit (1-5)
|
||||
@@ -378,6 +442,241 @@ token_consumption = "medium"
|
||||
default_active = true
|
||||
activation_warning = "Strategist hand runs continuously and performs strategic analysis, consuming tokens."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "策略分析 Hand"
|
||||
description = "自主策略分析师——市场研究、竞争分析、商业规划和战略建议"
|
||||
category = "生产力"
|
||||
|
||||
[i18n.zh.settings.focus_area]
|
||||
label = "聚焦方向"
|
||||
description = "战略分析的主要方向"
|
||||
|
||||
[i18n.zh.settings.analysis_depth]
|
||||
label = "分析深度"
|
||||
description = "每次战略分析的详尽程度"
|
||||
|
||||
[i18n.zh.settings.industry]
|
||||
label = "行业"
|
||||
description = "重点分析的行业(例如 SaaS、金融科技、医疗健康)"
|
||||
|
||||
[i18n.zh.settings.competitors]
|
||||
label = "主要竞争对手"
|
||||
description = "需要追踪的竞争对手列表(逗号分隔)"
|
||||
|
||||
[i18n.zh.settings.auto_monitor]
|
||||
label = "自动监控"
|
||||
description = "自动追踪竞争对手动态和市场变化"
|
||||
|
||||
[i18n.zh.settings.report_format]
|
||||
label = "报告格式"
|
||||
description = "战略报告的格式风格"
|
||||
|
||||
[i18n.zh.settings.confidence_threshold]
|
||||
label = "置信度阈值"
|
||||
description = "报告中纳入分析结论的最低置信度"
|
||||
|
||||
[i18n.zh.settings.frameworks]
|
||||
label = "首选分析框架"
|
||||
description = "优先使用的战略分析框架(逗号分隔,例如 SWOT,Porter,PESTEL)"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Estrategia"
|
||||
description = "Analista estratégico autónomo — investigación de mercado, análisis competitivo, planificación empresarial y recomendaciones estratégicas"
|
||||
category = "Productividad"
|
||||
|
||||
[i18n.es.settings.focus_area]
|
||||
label = "Área de enfoque"
|
||||
description = "Área principal del análisis estratégico"
|
||||
|
||||
[i18n.es.settings.analysis_depth]
|
||||
label = "Profundidad del análisis"
|
||||
description = "Nivel de detalle de cada análisis estratégico"
|
||||
|
||||
[i18n.es.settings.industry]
|
||||
label = "Industria"
|
||||
description = "Industria principal en la que enfocar el análisis (ej. SaaS, fintech, salud)"
|
||||
|
||||
[i18n.es.settings.competitors]
|
||||
label = "Competidores clave"
|
||||
description = "Lista de competidores a rastrear separados por comas"
|
||||
|
||||
[i18n.es.settings.auto_monitor]
|
||||
label = "Monitoreo automático"
|
||||
description = "Rastrear automáticamente movimientos de competidores y cambios del mercado"
|
||||
|
||||
[i18n.es.settings.report_format]
|
||||
label = "Formato de informe"
|
||||
description = "Formato de los informes estratégicos"
|
||||
|
||||
[i18n.es.settings.confidence_threshold]
|
||||
label = "Umbral de confianza"
|
||||
description = "Nivel mínimo de confianza para incluir hallazgos en los informes"
|
||||
|
||||
[i18n.es.settings.frameworks]
|
||||
label = "Marcos de análisis preferidos"
|
||||
description = "Marcos estratégicos a priorizar (separados por comas, ej. SWOT, Porter, PESTEL)"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "戦略分析 Hand"
|
||||
description = "自律型戦略アナリスト——市場調査、競合分析、事業計画、戦略的提言"
|
||||
category = "生産性"
|
||||
|
||||
[i18n.ja.settings.focus_area]
|
||||
label = "フォーカスエリア"
|
||||
description = "戦略分析の主な対象分野"
|
||||
|
||||
[i18n.ja.settings.analysis_depth]
|
||||
label = "分析の深さ"
|
||||
description = "各戦略分析の詳細度"
|
||||
|
||||
[i18n.ja.settings.industry]
|
||||
label = "業界"
|
||||
description = "分析の対象となる主要業界(例: SaaS、フィンテック、ヘルスケア)"
|
||||
|
||||
[i18n.ja.settings.competitors]
|
||||
label = "主要な競合"
|
||||
description = "追跡する競合のリスト(カンマ区切り)"
|
||||
|
||||
[i18n.ja.settings.auto_monitor]
|
||||
label = "自動監視"
|
||||
description = "競合の動向と市場の変化を自動的に追跡する"
|
||||
|
||||
[i18n.ja.settings.report_format]
|
||||
label = "レポート形式"
|
||||
description = "戦略レポートのフォーマット"
|
||||
|
||||
[i18n.ja.settings.confidence_threshold]
|
||||
label = "信頼度しきい値"
|
||||
description = "レポートに分析結果を含めるための最低信頼度"
|
||||
|
||||
[i18n.ja.settings.frameworks]
|
||||
label = "優先フレームワーク"
|
||||
description = "優先的に使用する戦略分析フレームワーク(カンマ区切り、例: SWOT,Porter,PESTEL)"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand Stratégique"
|
||||
description = "Analyste stratégique autonome — étude de marché, analyse concurrentielle, planification d'entreprise et recommandations stratégiques"
|
||||
category = "Productivité"
|
||||
|
||||
[i18n.fr.settings.focus_area]
|
||||
label = "Domaine d'intérêt"
|
||||
description = "Domaine principal de l'analyse stratégique"
|
||||
|
||||
[i18n.fr.settings.analysis_depth]
|
||||
label = "Profondeur d'analyse"
|
||||
description = "Niveau de détail de chaque analyse stratégique"
|
||||
|
||||
[i18n.fr.settings.industry]
|
||||
label = "Secteur"
|
||||
description = "Secteur principal d'analyse (ex. SaaS, fintech, santé)"
|
||||
|
||||
[i18n.fr.settings.competitors]
|
||||
label = "Concurrents clés"
|
||||
description = "Liste de concurrents à suivre séparée par des virgules"
|
||||
|
||||
[i18n.fr.settings.auto_monitor]
|
||||
label = "Surveillance automatique"
|
||||
description = "Suivre automatiquement les mouvements des concurrents et les évolutions du marché"
|
||||
|
||||
[i18n.fr.settings.report_format]
|
||||
label = "Format de rapport"
|
||||
description = "Format des rapports stratégiques"
|
||||
|
||||
[i18n.fr.settings.confidence_threshold]
|
||||
label = "Seuil de confiance"
|
||||
description = "Niveau de confiance minimum pour inclure les résultats dans les rapports"
|
||||
|
||||
[i18n.fr.settings.frameworks]
|
||||
label = "Cadres d'analyse préférés"
|
||||
description = "Cadres d'analyse stratégique à privilégier (séparés par des virgules, ex. SWOT, Porter, PESTEL)"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Strategie-Hand"
|
||||
description = "Autonomer Strategieanalyst — Marktforschung, Wettbewerbsanalyse, Geschäftsplanung und strategische Empfehlungen"
|
||||
category = "Produktivität"
|
||||
|
||||
[i18n.de.settings.focus_area]
|
||||
label = "Fokusbereich"
|
||||
description = "Hauptbereich der strategischen Analyse"
|
||||
|
||||
[i18n.de.settings.analysis_depth]
|
||||
label = "Analysetiefe"
|
||||
description = "Detailgrad jeder strategischen Analyse"
|
||||
|
||||
[i18n.de.settings.industry]
|
||||
label = "Branche"
|
||||
description = "Hauptbranche für die Analyse (z.B. SaaS, Fintech, Gesundheitswesen)"
|
||||
|
||||
[i18n.de.settings.competitors]
|
||||
label = "Wichtige Wettbewerber"
|
||||
description = "Kommagetrennte Liste der zu verfolgenden Wettbewerber"
|
||||
|
||||
[i18n.de.settings.auto_monitor]
|
||||
label = "Automatische Überwachung"
|
||||
description = "Wettbewerberbewegungen und Marktveränderungen automatisch verfolgen"
|
||||
|
||||
[i18n.de.settings.report_format]
|
||||
label = "Berichtsformat"
|
||||
description = "Format der Strategieberichte"
|
||||
|
||||
[i18n.de.settings.confidence_threshold]
|
||||
label = "Konfidenzschwelle"
|
||||
description = "Mindest-Konfidenzniveau für die Aufnahme von Ergebnissen in Berichte"
|
||||
|
||||
[i18n.de.settings.frameworks]
|
||||
label = "Bevorzugte Analyse-Frameworks"
|
||||
description = "Bevorzugte strategische Analyse-Frameworks (kommagetrennt, z.B. SWOT, Porter, PESTEL)"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "전략 분석 Hand"
|
||||
description = "자율 전략 분석가 — 시장 조사, 경쟁 분석, 사업 계획 및 전략적 권고"
|
||||
category = "생산성"
|
||||
|
||||
[i18n.ko.settings.focus_area]
|
||||
label = "집중 분야"
|
||||
description = "전략 분석의 주요 방향"
|
||||
|
||||
[i18n.ko.settings.analysis_depth]
|
||||
label = "분석 깊이"
|
||||
description = "각 전략 분석의 철저함 정도"
|
||||
|
||||
[i18n.ko.settings.industry]
|
||||
label = "산업"
|
||||
description = "분석의 중점 산업 (예: SaaS, 핀테크, 헬스케어)"
|
||||
|
||||
[i18n.ko.settings.competitors]
|
||||
label = "주요 경쟁사"
|
||||
description = "추적할 경쟁사 목록 (쉼표로 구분)"
|
||||
|
||||
[i18n.ko.settings.auto_monitor]
|
||||
label = "자동 모니터링"
|
||||
description = "경쟁사 동향 및 시장 변화를 자동으로 추적"
|
||||
|
||||
[i18n.ko.settings.report_format]
|
||||
label = "보고서 형식"
|
||||
description = "전략 보고서의 형식 스타일"
|
||||
|
||||
[i18n.ko.settings.confidence_threshold]
|
||||
label = "신뢰도 임계값"
|
||||
description = "보고서에 분석 결과를 포함하기 위한 최소 신뢰도"
|
||||
|
||||
[i18n.ko.settings.frameworks]
|
||||
label = "선호 분석 프레임워크"
|
||||
description = "우선적으로 사용할 전략 분석 프레임워크 (쉼표로 구분, 예: SWOT,Porter,PESTEL)"
|
||||
@@ -23,6 +23,16 @@ Best practices:
|
||||
- Prioritize: Rank items by impact
|
||||
- Cross-reference: Look for SO (strength-opportunity) and WT (weakness-threat) combinations
|
||||
- Action-oriented: Every SWOT item should suggest a strategic response
|
||||
- Time-bound: Note whether each factor is stable, strengthening, or weakening
|
||||
|
||||
**SWOT Cross-Impact Matrix** — The real value of SWOT is in the intersections:
|
||||
|
||||
| | Opportunities | Threats |
|
||||
|---|---|---|
|
||||
| **Strengths** | SO strategies: Use strengths to capture opportunities (offensive) | ST strategies: Use strengths to neutralize threats (defensive) |
|
||||
| **Weaknesses** | WO strategies: Fix weaknesses to unlock opportunities (investment) | WT strategies: Minimize weaknesses exposed by threats (survival) |
|
||||
|
||||
Prioritize: SO strategies first (highest ROI), then ST (protect position), then WO (selective investment), last WT (only if existential).
|
||||
|
||||
### Porter's Five Forces
|
||||
|
||||
@@ -36,6 +46,8 @@ Analyze industry attractiveness:
|
||||
|
||||
Rate each force: Low / Medium / High with supporting evidence.
|
||||
|
||||
**Dynamic Five Forces**: Forces change over time. For each force, note the **trend direction** (strengthening/stable/weakening) and the **trigger event** that could shift it. A force rated "Low" today with a strengthening trend deserves more attention than a stable "Medium" force.
|
||||
|
||||
### PESTEL Analysis
|
||||
|
||||
Macro-environmental scanning:
|
||||
@@ -49,6 +61,45 @@ Macro-environmental scanning:
|
||||
| **Environmental** | Climate regulations? Sustainability demands? Resource scarcity? |
|
||||
| **Legal** | Employment law? IP protection? Competition law? Data privacy? |
|
||||
|
||||
### Framework Integration Methodology
|
||||
|
||||
Individual frameworks are lenses. Strategic insight comes from combining them. Here is how to synthesize multiple frameworks into a unified analysis:
|
||||
|
||||
**The Integration Cascade** — Use frameworks in dependency order:
|
||||
|
||||
```
|
||||
Step 1: PESTEL (macro context)
|
||||
→ Identifies external forces shaping the industry
|
||||
→ Output: Which macro factors matter most? What is changing?
|
||||
|
||||
Step 2: Porter's Five Forces (industry structure)
|
||||
→ PESTEL outputs feed directly into Porter's forces
|
||||
→ Example: "AI adoption accelerating" (PESTEL-Tech) → "Threat of new entrants rising" (Porter)
|
||||
→ Output: How attractive is this industry? Where is structural power?
|
||||
|
||||
Step 3: SWOT (company positioning within industry)
|
||||
→ Porter's outputs define the external O/T quadrants
|
||||
→ Internal assessment (S/W) is company-specific
|
||||
→ Output: Where does this company sit relative to industry forces?
|
||||
|
||||
Step 4: Strategic Options Generation
|
||||
→ SWOT cross-impact matrix generates candidate strategies
|
||||
→ Porter's forces identify which strategies are structurally viable
|
||||
→ PESTEL trends determine timing and urgency
|
||||
```
|
||||
|
||||
**Cross-Framework Contradiction Resolution:**
|
||||
When frameworks disagree, do not average or ignore — investigate:
|
||||
- PESTEL says favorable + Porter says unattractive → Macro tailwind but bad industry structure (e.g., restaurant industry: everyone eats, but margins are terrible)
|
||||
- SWOT says strong + Porter says high rivalry → Company advantage may erode faster than expected
|
||||
- Resolution: State both findings, explain the tension, and let the tension inform the recommendation (e.g., "Enter but with a differentiation strategy that exploits the macro trend while avoiding head-on competition")
|
||||
|
||||
**Synthesis Quality Checklist:**
|
||||
- Does the conclusion follow logically from framework outputs, or did you skip to a preferred answer?
|
||||
- Did you weight frameworks by relevance (PESTEL matters more for market entry; Porter matters more for competitive strategy)?
|
||||
- Are the frameworks consistent? If not, is the inconsistency explained?
|
||||
- Could someone reconstruct your reasoning by reading the framework outputs alone?
|
||||
|
||||
### Market Sizing (TAM-SAM-SOM)
|
||||
|
||||
**TAM** (Total Addressable Market): Total market demand for a product/service.
|
||||
@@ -236,3 +287,814 @@ Employee Count: [Growth indicator]
|
||||
## Implementation
|
||||
[How to execute the recommendation]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: B2B SaaS Market Entry into Japan
|
||||
|
||||
**Context**: A US-based B2B SaaS company (project management tool, $15M ARR, 200 employees) evaluating entry into the Japanese market.
|
||||
|
||||
**PESTEL Analysis — Japan B2B SaaS (2025):**
|
||||
|
||||
| Factor | Assessment | Impact | Score (1-5) |
|
||||
|--------|-----------|--------|-------------|
|
||||
| **Political** | Stable democracy; strong US-Japan trade relations; Digital Agency pushing government digitization | Positive | 4 |
|
||||
| **Economic** | GDP $4.2T; weak yen (150 JPY/USD) makes USD-priced SaaS expensive; enterprise IT spend growing 4% YoY | Mixed | 3 |
|
||||
| **Social** | Aging workforce accelerates automation need; consensus-driven decision making lengthens sales cycles (avg 6-9 months); strong preference for local-language support | Critical constraint | 2 |
|
||||
| **Technological** | High internet penetration (93%); cloud adoption lagging US by 3-5 years but accelerating; 5G rollout complete in urban areas | Opportunity | 4 |
|
||||
| **Environmental** | ESG reporting mandated for listed companies from 2023; sustainability-linked procurement gaining traction | Moderate opportunity | 3 |
|
||||
| **Legal** | APPI (Act on Protection of Personal Information) requires data residency consideration; strict labor laws affect HR SaaS | Compliance cost | 2 |
|
||||
|
||||
**PESTEL Score**: 18/30 — Moderately favorable. Key risk: social/cultural factors demand significant localization investment.
|
||||
|
||||
**Porter's Five Forces — Japan Project Management SaaS:**
|
||||
|
||||
| Force | Rating | Evidence |
|
||||
|-------|--------|---------|
|
||||
| New Entrants | 2/5 | High localization cost ($500K-$1M); relationship-driven market favors incumbents |
|
||||
| Supplier Power | 1/5 | Cloud infrastructure (AWS Tokyo, Azure Japan) is commodity; no supplier concentration |
|
||||
| Buyer Power | 4/5 | Enterprise buyers demand customization; long procurement cycles give buyers leverage; RFP-driven purchasing |
|
||||
| Substitutes | 3/5 | Excel/spreadsheet culture deeply entrenched; domestic tools (Backlog, Jooto) have cultural fit advantage |
|
||||
| Rivalry | 4/5 | Asana, Monday.com, Notion already present; domestic players Backlog (Nulab) and Redmine have loyal bases |
|
||||
|
||||
**Go-to-Market Recommendation:**
|
||||
|
||||
```
|
||||
Strategy: Partner-Led Entry (not direct sales)
|
||||
Timeline: 18 months to first enterprise deal
|
||||
|
||||
Phase 1 (Months 1-6): Foundation
|
||||
- Hire Country Manager (must be bilingual Japanese national)
|
||||
- Full UI/UX localization (not just translation — date formats, name order, honorifics)
|
||||
- Achieve ISMAP certification (required for government/enterprise procurement)
|
||||
- Data residency: Deploy on AWS Tokyo region
|
||||
- Budget: $800K
|
||||
|
||||
Phase 2 (Months 4-12): Channel Development
|
||||
- Sign 2-3 SIer (System Integrator) partners: target NTT Data, Fujitsu, NEC
|
||||
- Japanese SIers control 60% of enterprise software purchasing decisions
|
||||
- Co-develop integration with domestic tools (kintone, Sansan, freee)
|
||||
- Budget: $600K (partner enablement + integration development)
|
||||
|
||||
Phase 3 (Months 8-18): Market Penetration
|
||||
- Target mid-market first (500-2000 employees) — faster decision cycles than enterprise
|
||||
- Launch at Japan IT Week (Spring/Autumn) and SaaS Industry Conference
|
||||
- Content marketing: Japanese-language case studies, webinars with local customers
|
||||
- Target: 20 paying customers, $500K ARR by month 18
|
||||
- Budget: $400K
|
||||
|
||||
Total Investment: $1.8M over 18 months
|
||||
Break-even: Month 30 (projected)
|
||||
```
|
||||
|
||||
**Decision**: Proceed with caution. The $4.2T economy and cloud adoption tailwind justify the investment, but only with proper localization and channel strategy. Direct sales without SIer partnerships has a historically high failure rate (>70% for foreign SaaS in Japan).
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Competitive Response — Major Player Enters Your Niche
|
||||
|
||||
**Context**: You run a $5M ARR vertical SaaS for veterinary clinics (500 customers, 15% market share). Salesforce just announced "Salesforce for Veterinary" — a vertical solution built on their platform.
|
||||
|
||||
**Threat Assessment:**
|
||||
|
||||
| Dimension | Your Position | Salesforce | Gap |
|
||||
|-----------|--------------|------------|-----|
|
||||
| Brand recognition | Niche leader | Global enterprise brand | Large — but irrelevant in vet niche |
|
||||
| Product depth | Purpose-built (8 years domain expertise) | Horizontal platform with vertical skin | Strong advantage |
|
||||
| Price point | $200/mo per clinic | $500/mo estimated (Salesforce pricing) | 2.5x cheaper |
|
||||
| Implementation time | 2 weeks | 3-6 months (typical SF implementation) | Strong advantage |
|
||||
| Integration depth | Deep PMS/PIMS integration | API-based, requires middleware | Strong advantage |
|
||||
| Sales motion | Direct + word-of-mouth | Enterprise sales team + SI partners | Different segments |
|
||||
| Switching cost for your customers | Moderate (data migration + retraining) | High (Salesforce ecosystem lock-in) | Neutral |
|
||||
|
||||
**Strategic Response Framework:**
|
||||
|
||||
```
|
||||
IMMEDIATE (Week 1-4): Defend the Base
|
||||
1. Customer communication campaign
|
||||
- CEO letter to all 500 customers: "Our commitment to veterinary"
|
||||
- Emphasize: purpose-built > horizontal platform
|
||||
- Announce product roadmap acceleration
|
||||
|
||||
2. Lock in at-risk accounts
|
||||
- Identify top 50 accounts by revenue
|
||||
- Offer annual contract discounts (15-20% for 2-year commitment)
|
||||
- Schedule QBRs with all enterprise accounts within 30 days
|
||||
|
||||
3. Competitive battle card
|
||||
- Create internal sales doc: feature-by-feature comparison
|
||||
- "Why vets choose us over Salesforce" — 5 key differentiators
|
||||
- Objection handling for "shouldn't we go with the safe choice?"
|
||||
|
||||
SHORT-TERM (Month 2-6): Deepen the Moat
|
||||
4. Accelerate domain-specific features
|
||||
- AI-powered treatment plan suggestions (Salesforce can't match this)
|
||||
- Telemedicine integration (vertical-specific)
|
||||
- Inventory management tied to treatment protocols
|
||||
|
||||
5. Build switching costs
|
||||
- Launch data analytics dashboard (clinics depend on historical trends)
|
||||
- Introduce multi-location management (target growing chains)
|
||||
- API marketplace for vet-specific integrations (lab equipment, imaging)
|
||||
|
||||
6. Community defense
|
||||
- Launch "Vet Tech Community" — user forum + knowledge base
|
||||
- Annual user conference (even virtual — creates tribal loyalty)
|
||||
- Customer advisory board (top 10 clinics = co-development partners)
|
||||
|
||||
MEDIUM-TERM (Month 6-18): Counterattack
|
||||
7. Move upmarket selectively
|
||||
- Enterprise tier for 10+ location chains ($500/mo — match SF pricing)
|
||||
- Offer white-glove migration from legacy systems
|
||||
- This is the segment Salesforce will target — contest it
|
||||
|
||||
8. Geographic expansion
|
||||
- Salesforce announcement creates awareness of the category
|
||||
- Ride the wave: "Already purpose-built, already proven"
|
||||
- Target UK, Australia, Canada (English-speaking, similar vet market structure)
|
||||
```
|
||||
|
||||
**Pricing Response Decision Matrix:**
|
||||
|
||||
| Option | Revenue Impact | Competitive Effect | Risk |
|
||||
|--------|---------------|-------------------|------|
|
||||
| No change | Neutral | Salesforce still 2.5x more expensive | Low — price isn't the battleground |
|
||||
| Cut prices 20% | -$1M ARR | Signals weakness; Salesforce won't match | High |
|
||||
| Add premium tier | +$500K potential | Compete at enterprise level; justify R&D | Medium |
|
||||
| Usage-based addon | +$300K potential | Expand ARPU without base price war | Low |
|
||||
|
||||
**Recommendation**: Add premium tier + usage-based addons. Do NOT cut base prices. Salesforce's entry validates your market — use it to raise your valuation narrative ("Salesforce sees a $2B market opportunity in vet SaaS — we already own 15%").
|
||||
|
||||
**Confidence**: Medium-High (75%) — Historical pattern: when Salesforce enters verticals, purpose-built incumbents retain 80%+ of existing customers. Risk is in new customer acquisition where brand matters more.
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Platform Sunset Decision — Migrate or Maintain Legacy Product
|
||||
|
||||
**Context**: A mid-stage startup ($20M ARR) runs two products: a legacy desktop app (60% of revenue, declining 10% YoY) and a modern cloud product (40% of revenue, growing 50% YoY). Should they sunset the desktop app?
|
||||
|
||||
**Decision Matrix:**
|
||||
|
||||
| Criterion (Weight) | Option A: Maintain Both | Option B: Sunset in 12mo | Option C: Sunset in 24mo |
|
||||
|--------------------|------------------------|--------------------------|--------------------------|
|
||||
| Revenue protection (30%) | 5 — No disruption | 2 — Lose 40% of legacy revenue | 4 — Gradual migration |
|
||||
| Engineering efficiency (25%) | 1 — Two codebases drain resources | 5 — Full focus on cloud | 3 — Phased transition |
|
||||
| Customer satisfaction (20%) | 3 — Legacy stagnates | 2 — Forced migration angers users | 4 — Supported migration path |
|
||||
| Market positioning (15%) | 2 — Confused narrative | 5 — Clear cloud-first story | 4 — Transitional narrative |
|
||||
| Financial risk (10%) | 3 — Slow bleed sustainable | 2 — Revenue cliff risk | 4 — Manageable decline |
|
||||
| **Weighted Score** | **2.95** | **3.35** | **3.75** |
|
||||
|
||||
**Recommendation**: Option C — 24-month sunset with structured migration program.
|
||||
|
||||
```
|
||||
Migration Program:
|
||||
Months 1-6: Feature parity audit; build top 20 missing cloud features
|
||||
Months 7-12: Migration incentive (20% discount for annual cloud commitment)
|
||||
Months 13-18: Desktop enters maintenance-only mode; no new features
|
||||
Months 19-24: End-of-life announcement; dedicated migration support team
|
||||
Month 24: Desktop product sunsets; legacy support for 6 more months
|
||||
|
||||
Financial Model:
|
||||
Current state: $12M desktop + $8M cloud = $20M ARR
|
||||
Month 12 (projected): $9M desktop + $14M cloud = $23M ARR
|
||||
Month 24 (projected): $2M desktop + $22M cloud = $24M ARR
|
||||
Month 30 (projected): $0 desktop + $26M cloud = $26M ARR
|
||||
|
||||
Net ARR risk: ~$3M from non-migrating desktop customers
|
||||
Offset: Engineering savings of $1.5M/yr + faster cloud feature velocity
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Financial Analysis Frameworks
|
||||
|
||||
### Unit Economics
|
||||
|
||||
Core metrics every strategy should quantify:
|
||||
|
||||
```
|
||||
CAC (Customer Acquisition Cost)
|
||||
= Total Sales & Marketing Spend / New Customers Acquired
|
||||
Example: $500K spend / 100 new customers = $5,000 CAC
|
||||
|
||||
LTV (Lifetime Value)
|
||||
= ARPU x Gross Margin % x (1 / Churn Rate)
|
||||
Example: $500/mo x 80% x (1 / 0.03) = $13,333 LTV
|
||||
|
||||
LTV:CAC Ratio
|
||||
Target: > 3:1 for healthy SaaS
|
||||
Example: $13,333 / $5,000 = 2.67:1 (below target — reduce CAC or increase retention)
|
||||
|
||||
CAC Payback Period
|
||||
= CAC / (ARPU x Gross Margin %)
|
||||
Example: $5,000 / ($500 x 0.80) = 12.5 months
|
||||
Target: < 18 months for SaaS
|
||||
```
|
||||
|
||||
**Unit Economics Health Check:**
|
||||
|
||||
| Metric | Danger Zone | Acceptable | Excellent |
|
||||
|--------|------------|------------|-----------|
|
||||
| LTV:CAC | < 1:1 | 3:1 | > 5:1 |
|
||||
| CAC Payback | > 24 months | 12-18 months | < 12 months |
|
||||
| Gross Margin | < 60% | 70-80% | > 80% |
|
||||
| Net Revenue Retention | < 90% | 100-110% | > 120% |
|
||||
| Logo Churn (monthly) | > 5% | 2-3% | < 1% |
|
||||
|
||||
### Revenue Modeling
|
||||
|
||||
**SaaS Revenue Waterfall:**
|
||||
|
||||
```
|
||||
Beginning ARR: $10,000,000
|
||||
+ New Business: +$3,000,000 (new logos)
|
||||
+ Expansion: +$1,500,000 (upsell/cross-sell)
|
||||
- Contraction: -$500,000 (downgrades)
|
||||
- Churn: -$1,200,000 (lost customers)
|
||||
= Ending ARR: $12,800,000
|
||||
|
||||
Net New ARR: $2,800,000
|
||||
Net Revenue Retention: 113% = ($10M + $1.5M - $0.5M - $1.2M) / $10M
|
||||
Gross Revenue Retention: 88% = ($10M - $0.5M - $1.2M) / $10M
|
||||
```
|
||||
|
||||
**MRR Growth Decomposition:**
|
||||
|
||||
```
|
||||
MRR Growth Rate = New MRR + Expansion MRR - Churned MRR - Contraction MRR
|
||||
─────────────────────────────────────────────────────────
|
||||
Beginning MRR
|
||||
|
||||
Quick Ratio = (New MRR + Expansion MRR) / (Churned MRR + Contraction MRR)
|
||||
Target: > 4 for high-growth SaaS
|
||||
```
|
||||
|
||||
### Break-Even Analysis
|
||||
|
||||
```
|
||||
Break-Even Revenue = Fixed Costs / Gross Margin %
|
||||
|
||||
Example:
|
||||
Fixed Costs (monthly): $200K (salaries, rent, tools)
|
||||
Gross Margin: 80%
|
||||
Break-Even Revenue = $200K / 0.80 = $250K/month = $3M ARR
|
||||
|
||||
Break-Even Customers = Break-Even Revenue / ARPU
|
||||
= $250K / $500 = 500 customers
|
||||
```
|
||||
|
||||
**Scenario Table:**
|
||||
|
||||
| Scenario | Fixed Costs | Gross Margin | Break-Even ARR | Break-Even Customers |
|
||||
|----------|------------|--------------|-----------------|---------------------|
|
||||
| Lean | $150K/mo | 85% | $2.1M | 353 |
|
||||
| Base | $200K/mo | 80% | $3.0M | 500 |
|
||||
| Growth | $350K/mo | 75% | $5.6M | 933 |
|
||||
|
||||
### Project Evaluation — Simplified DCF
|
||||
|
||||
Use for evaluating strategic investments (new market entry, build vs buy, major feature investment):
|
||||
|
||||
```
|
||||
NPV = Σ [Cash Flow_t / (1 + r)^t] - Initial Investment
|
||||
|
||||
Where:
|
||||
r = discount rate (typically 10-15% for startups, 8-10% for established companies)
|
||||
t = year (0, 1, 2, ... n)
|
||||
```
|
||||
|
||||
**Worked Example — Should we build a mobile app?**
|
||||
|
||||
```
|
||||
Initial Investment: $500K (development cost)
|
||||
Discount Rate: 12%
|
||||
|
||||
Year | Incremental Revenue | Incremental Cost | Net Cash Flow | PV Factor | Present Value
|
||||
------|--------------------|--------------------|---------------|-----------|-------------
|
||||
0 | $0 | $500,000 | -$500,000 | 1.000 | -$500,000
|
||||
1 | $200,000 | $80,000 | $120,000 | 0.893 | $107,143
|
||||
2 | $400,000 | $100,000 | $300,000 | 0.797 | $239,158
|
||||
3 | $600,000 | $120,000 | $480,000 | 0.712 | $341,655
|
||||
4 | $700,000 | $130,000 | $570,000 | 0.636 | $362,204
|
||||
|
||||
NPV = $550,160 → Positive NPV → Project is financially justified
|
||||
Payback Period: ~2.3 years (cumulative cash flow turns positive in Year 3)
|
||||
```
|
||||
|
||||
**Decision Rule:**
|
||||
- NPV > 0 → Proceed (project creates value)
|
||||
- NPV < 0 → Reject (project destroys value)
|
||||
- Compare NPV across mutually exclusive options; pick highest
|
||||
|
||||
---
|
||||
|
||||
## Go-to-Market Strategy Patterns
|
||||
|
||||
### Growth Motion Selection
|
||||
|
||||
| Growth Motion | Best For | Sales Cycle | CAC | Key Metric |
|
||||
|--------------|---------|-------------|-----|------------|
|
||||
| **Product-Led Growth (PLG)** | Self-serve products; low price point (<$500/mo); individual users | Minutes to days | Low ($50-$500) | Activation rate, PQL conversion |
|
||||
| **Sales-Led Growth** | Enterprise products; complex deployment; >$50K ACV | Weeks to months | High ($5K-$50K) | Pipeline velocity, win rate |
|
||||
| **Community-Led Growth** | Developer tools; open-source; platform products | Varies | Very low ($10-$100) | Community size, contribution rate |
|
||||
| **Partner-Led Growth** | Market entry; regulated industries; ecosystem products | Varies | Medium ($1K-$10K) | Partner-sourced revenue % |
|
||||
|
||||
**PLG Funnel:**
|
||||
```
|
||||
Visitor → Sign-up → Activated User → PQL → Paid Customer → Expanded Account
|
||||
100% 10% 40% 25% 15% 30%
|
||||
|
||||
Key levers:
|
||||
- Sign-up friction: Reduce form fields, add SSO
|
||||
- Time-to-value: Get user to "aha moment" in < 5 minutes
|
||||
- PQL definition: User hits usage threshold that correlates with purchase
|
||||
- Expansion trigger: Team features, usage limits, premium capabilities
|
||||
```
|
||||
|
||||
**Sales-Led Funnel:**
|
||||
```
|
||||
Lead → MQL → SQL → Opportunity → Proposal → Closed Won
|
||||
100% 20% 50% 60% 70% 30%
|
||||
|
||||
Key levers:
|
||||
- Lead quality: ICP fit scoring
|
||||
- MQL→SQL handoff: Alignment between marketing and sales
|
||||
- Discovery: Deep pain identification
|
||||
- Champion building: Enable internal advocate
|
||||
- Procurement: Legal/security review preparation
|
||||
```
|
||||
|
||||
### Pricing Strategy Frameworks
|
||||
|
||||
**Value-Based Pricing (recommended for most SaaS):**
|
||||
```
|
||||
1. Quantify customer value created
|
||||
Example: Your tool saves 10 hours/week per user
|
||||
Value = 10 hrs x $75/hr x 52 weeks = $39,000/year
|
||||
|
||||
2. Capture 10-20% of value created
|
||||
Price = $39,000 x 15% = $5,850/year = $487/month
|
||||
|
||||
3. Validate with willingness-to-pay research
|
||||
Van Westendorp Price Sensitivity Meter:
|
||||
- "At what price is this too expensive?" → $600/mo
|
||||
- "At what price is this a bargain?" → $200/mo
|
||||
- "At what price does it seem expensive but you'd still consider?" → $450/mo
|
||||
- "At what price does it seem too cheap to trust?" → $100/mo
|
||||
→ Optimal price range: $200-$450/mo
|
||||
```
|
||||
|
||||
**Pricing Tier Architecture:**
|
||||
|
||||
```
|
||||
Tier Structure (Good-Better-Best):
|
||||
|
||||
| | Starter | Professional | Enterprise |
|
||||
|---|---------|-------------|------------|
|
||||
| Target | Individual/SMB | Mid-market team | Large organization |
|
||||
| Price | $29/mo | $99/mo/user | Custom (>$500/mo) |
|
||||
| Anchor role | Drive adoption | Revenue driver (~60% of revenue) | Margin driver |
|
||||
| Features | Core functionality | Full platform | Custom + SLA + support |
|
||||
| Support | Self-serve/email | Priority email + chat | Dedicated CSM + phone |
|
||||
| Billing | Monthly/Annual | Annual preferred | Annual contract |
|
||||
|
||||
Design principles:
|
||||
- Middle tier should be the obvious best value
|
||||
- Top tier exists to make middle tier look reasonable (anchoring effect)
|
||||
- Feature gates should align with natural usage growth
|
||||
- Price metric should scale with value received (per user, per GB, per transaction)
|
||||
```
|
||||
|
||||
**Competitive Pricing Analysis:**
|
||||
|
||||
```
|
||||
Competitor Price Map:
|
||||
|
||||
Competitor | Entry Price | Mid-Tier | Enterprise | Price Metric
|
||||
-------------|-------------|----------|------------|-------------
|
||||
Competitor A | $49/mo | $149/mo | Custom | Per user
|
||||
Competitor B | $0 (free) | $99/mo | $299/mo | Flat rate
|
||||
Competitor C | $29/mo | $79/mo | Custom | Per user
|
||||
Your Product | ??? | ??? | ??? | ???
|
||||
|
||||
Positioning options:
|
||||
- Price leader: 20-30% below average → requires cost advantage
|
||||
- Value leader: At or above average → requires clear differentiation
|
||||
- Premium: 30%+ above average → requires brand and feature superiority
|
||||
```
|
||||
|
||||
### Channel Strategy
|
||||
|
||||
| Channel | Margin | Control | Scale | Best For |
|
||||
|---------|--------|---------|-------|----------|
|
||||
| Direct sales | High (85-95%) | Full | Slow | Enterprise, complex products |
|
||||
| Inside sales | High (80-90%) | Full | Medium | Mid-market, $5K-$50K ACV |
|
||||
| Self-serve | Highest (95%+) | Full | Fast | PLG, low ACV |
|
||||
| Reseller/VAR | Low (60-70%) | Medium | Medium | Regional coverage, compliance |
|
||||
| Marketplace (AWS/Azure) | Low (70-85%) | Low | Fast | Enterprise procurement shortcuts |
|
||||
| System Integrator | Low (50-70%) | Low | Medium | Complex implementations |
|
||||
| Affiliate/Referral | High (80-90%) | Low | Fast | Consumer, SMB |
|
||||
|
||||
### Launch Playbook Template
|
||||
|
||||
```
|
||||
LAUNCH PLAYBOOK: [Product/Feature Name]
|
||||
Launch Date: YYYY-MM-DD
|
||||
Launch Type: [Major / Minor / Feature / Beta]
|
||||
|
||||
PRE-LAUNCH (T-8 weeks to T-0)
|
||||
Week -8: Finalize positioning and messaging
|
||||
Week -6: Create sales enablement materials (battle cards, one-pagers, demo script)
|
||||
Week -4: Brief analyst relations (Gartner, Forrester) if applicable
|
||||
Week -3: Seed beta customers (5-10 design partners); collect testimonials
|
||||
Week -2: Pre-brief press/media under embargo
|
||||
Week -1: Internal all-hands; sales team training; support team training
|
||||
|
||||
LAUNCH DAY (T-0)
|
||||
- Blog post (SEO-optimized)
|
||||
- Email to customer base
|
||||
- Social media campaign (LinkedIn, Twitter/X)
|
||||
- Press release (if major launch)
|
||||
- Product Hunt submission (if applicable)
|
||||
- In-app announcement for existing users
|
||||
- Founder/CEO LinkedIn post (highest engagement channel)
|
||||
|
||||
POST-LAUNCH (T+1 to T+8 weeks)
|
||||
Week +1: Monitor activation metrics; respond to all feedback
|
||||
Week +2: Publish customer case study
|
||||
Week +4: Webinar / live demo for pipeline
|
||||
Week +6: Analyze launch metrics vs targets
|
||||
Week +8: Retrospective and iteration plan
|
||||
|
||||
METRICS TO TRACK:
|
||||
- Awareness: Blog views, social impressions, press mentions
|
||||
- Activation: Sign-ups, trial starts, feature adoption rate
|
||||
- Revenue: Pipeline generated, deals influenced, new ARR
|
||||
- Sentiment: NPS from beta users, social sentiment, support ticket volume
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scenario Planning
|
||||
|
||||
### Best / Base / Worst Case Framework
|
||||
|
||||
Structure every major strategic decision with three scenarios:
|
||||
|
||||
```
|
||||
SCENARIO PLANNING: [Decision or Initiative]
|
||||
|
||||
| Worst Case | Base Case | Best Case
|
||||
--------------------|-----------------|-----------------|------------------
|
||||
Revenue impact | [quantify] | [quantify] | [quantify]
|
||||
Timeline | [duration] | [duration] | [duration]
|
||||
Key assumption | [what goes wrong]| [most likely] | [what goes right]
|
||||
Probability | [15-25%] | [50-60%] | [15-25%]
|
||||
Trigger indicators | [early signals] | [tracking metrics]| [early signals]
|
||||
Response plan | [pivot/exit] | [continue/adjust]| [accelerate/expand]
|
||||
```
|
||||
|
||||
**Worked Example — Launching a New Product Line:**
|
||||
|
||||
```
|
||||
SCENARIO PLANNING: Launch enterprise analytics add-on ($200/mo)
|
||||
|
||||
| Worst Case (20%) | Base Case (55%) | Best Case (25%)
|
||||
--------------------|-------------------|-------------------|-------------------
|
||||
Adoption rate | 5% of customers | 15% of customers | 30% of customers
|
||||
Year 1 revenue | $120K | $360K | $720K
|
||||
Development cost | $400K | $400K | $400K
|
||||
Year 1 ROI | -70% | -10% | +80%
|
||||
Break-even | Never (kill it) | Month 18 | Month 8
|
||||
Key assumption | Customers don't | Moderate demand; | Strong demand;
|
||||
| see value; churn | gradual adoption | pulls forward
|
||||
| increases 2% | | enterprise deals
|
||||
|
||||
Trigger Indicators:
|
||||
Worst: < 3% adoption after 3 months; NPS < 20 for add-on
|
||||
Base: 8-12% adoption after 3 months; positive but slow pipeline
|
||||
Best: > 20% adoption after 3 months; inbound enterprise interest
|
||||
|
||||
Response Plans:
|
||||
Worst: Pivot to bundling analytics into existing plan (retention play)
|
||||
Base: Continue; invest in onboarding and customer education
|
||||
Best: Hire dedicated analytics PM; accelerate roadmap; raise prices 20%
|
||||
```
|
||||
|
||||
**Expected Value Calculation:**
|
||||
|
||||
```
|
||||
Expected Revenue = (Worst Revenue x Worst Prob) + (Base Revenue x Base Prob) + (Best Revenue x Best Prob)
|
||||
= ($120K x 0.20) + ($360K x 0.55) + ($720K x 0.25)
|
||||
= $24K + $198K + $180K
|
||||
= $402K
|
||||
|
||||
Expected ROI = ($402K - $400K) / $400K = 0.5%
|
||||
→ Marginal on expected value alone — proceed only if strategic upside justifies the bet
|
||||
```
|
||||
|
||||
### Sensitivity Analysis
|
||||
|
||||
Identify which variables have the highest impact on outcomes:
|
||||
|
||||
```
|
||||
SENSITIVITY ANALYSIS: New Market Entry
|
||||
|
||||
Base Case NPV: $550K
|
||||
|
||||
Variable | -20% Change | Base | +20% Change | Sensitivity
|
||||
--------------------|---------------|----------|----------------|------------
|
||||
Customer price | $280K (-49%) | $550K | $820K (+49%) | HIGH
|
||||
Customer volume | $310K (-44%) | $550K | $790K (+44%) | HIGH
|
||||
Churn rate | $720K (+31%) | $550K | $380K (-31%) | HIGH
|
||||
Development cost | $650K (+18%) | $550K | $450K (-18%) | MEDIUM
|
||||
CAC | $610K (+11%) | $550K | $490K (-11%) | MEDIUM
|
||||
Discount rate | $590K (+7%) | $550K | $510K (-7%) | LOW
|
||||
```
|
||||
|
||||
**Interpretation**: Price and volume are the highest-leverage variables. Strategy should prioritize pricing power and demand generation over cost optimization.
|
||||
|
||||
**Tornado Chart Format (text representation):**
|
||||
|
||||
```
|
||||
Variable Impact on NPV (base = $550K):
|
||||
|
||||
Customer price |████████████████████| -49% to +49%
|
||||
Customer volume |███████████████████ | -44% to +44%
|
||||
Churn rate |██████████████ | -31% to +31%
|
||||
Development cost |█████████ | -18% to +18%
|
||||
CAC |██████ | -11% to +11%
|
||||
Discount rate |████ | -7% to +7%
|
||||
```
|
||||
|
||||
### Risk-Adjusted Decision Making
|
||||
|
||||
**Risk Register Template:**
|
||||
|
||||
| Risk | Probability (1-5) | Impact (1-5) | Risk Score | Mitigation | Residual Risk |
|
||||
|------|-------------------|-------------|------------|------------|---------------|
|
||||
| Key hire doesn't work out | 3 | 4 | 12 | Pipeline of 2 backup candidates | 6 |
|
||||
| Competitor launches first | 4 | 3 | 12 | Focus on differentiation not speed | 8 |
|
||||
| Technical architecture fails to scale | 2 | 5 | 10 | Prototype load test at 10x before commit | 4 |
|
||||
| Regulatory change blocks approach | 1 | 5 | 5 | Legal review + pivot plan documented | 3 |
|
||||
| Customer demand lower than projected | 3 | 4 | 12 | Pre-sell to 10 design partners before building | 6 |
|
||||
|
||||
**Risk-Adjusted NPV:**
|
||||
```
|
||||
Risk-Adjusted NPV = Base NPV x (1 - Risk Discount)
|
||||
|
||||
Where Risk Discount = Σ (Probability x Impact x Weight) for all material risks
|
||||
|
||||
Example:
|
||||
Base NPV: $550K
|
||||
Combined risk score: 0.15 (derived from risk register)
|
||||
Risk-Adjusted NPV: $550K x (1 - 0.15) = $467.5K
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Industry Analysis Templates
|
||||
|
||||
### Market Landscape Map
|
||||
|
||||
Plot all players in a market on two strategic dimensions:
|
||||
|
||||
```
|
||||
MARKET LANDSCAPE: [Industry/Category]
|
||||
|
||||
Enterprise-Grade
|
||||
|
|
||||
Quadrant 2| Quadrant 1
|
||||
Niche | Market Leaders
|
||||
Enterprise|
|
||||
Narrow ──────────────┼────────────── Broad
|
||||
Solution | Platform
|
||||
Quadrant 3| Quadrant 4
|
||||
Point | Mass-Market
|
||||
Solutions | Platforms
|
||||
|
|
||||
SMB-Focused
|
||||
|
||||
Example — Project Management SaaS (2025):
|
||||
|
||||
Quadrant 1 (Leaders): Asana, Monday.com, Smartsheet
|
||||
Quadrant 2 (Niche): Targetprocess (SAFe), Planview (PPM), Kantata (services)
|
||||
Quadrant 3 (Point): Todoist, Basecamp, Trello
|
||||
Quadrant 4 (Platforms): Notion, ClickUp, Microsoft Planner
|
||||
|
||||
Your Position: [X]
|
||||
Desired Position: [→ direction of strategic movement]
|
||||
```
|
||||
|
||||
**Building a Landscape Map:**
|
||||
|
||||
1. Select two dimensions that represent the most important strategic trade-offs in the market
|
||||
2. Commonly used axes:
|
||||
- Price / Complexity
|
||||
- Breadth of platform / Depth of solution
|
||||
- Enterprise / SMB focus
|
||||
- Horizontal / Vertical specialization
|
||||
- Self-serve / High-touch
|
||||
3. Plot all known competitors (minimum 8-10 for useful map)
|
||||
4. Identify white space — under-served quadrant combinations
|
||||
5. Draw your strategic vector — where are you moving and why?
|
||||
|
||||
### Technology Adoption Lifecycle Positioning
|
||||
|
||||
```
|
||||
THE ADOPTION CURVE:
|
||||
|
||||
Innovators Early Early Late Laggards
|
||||
(2.5%) Adopters Majority Majority (16%)
|
||||
(13.5%) (34%) (34%)
|
||||
___
|
||||
/ \
|
||||
/ \____
|
||||
/ \________
|
||||
/ \_________
|
||||
/ \___
|
||||
|
||||
↑ ↑
|
||||
THE CHASM MAINSTREAM
|
||||
(biggest (revenue
|
||||
risk point) acceleration)
|
||||
```
|
||||
|
||||
**Positioning by Stage:**
|
||||
|
||||
| Stage | Customer Profile | Sales Approach | Pricing Strategy | Key Risk |
|
||||
|-------|-----------------|----------------|------------------|----------|
|
||||
| Innovators | Tech enthusiasts; will tolerate bugs | Community; direct outreach | Free/very low; usage-based | Building for wrong use case |
|
||||
| Early Adopters | Visionaries; want competitive advantage | Consultative selling; pilots | Value-based; ROI-justified | Chasm — can't cross to mainstream |
|
||||
| Early Majority | Pragmatists; want proven solutions | References; case studies; demos | Competitive; published pricing | Scaling sales and support |
|
||||
| Late Majority | Conservatives; want complete solutions | Standard procurement; RFPs | Bundled; enterprise agreements | Margin compression |
|
||||
| Laggards | Skeptics; forced by circumstance | Compliance-driven; mandates | Legacy pricing; long contracts | Market is commoditizing |
|
||||
|
||||
**Chasm-Crossing Checklist:**
|
||||
```
|
||||
□ Whole product: Does the product solve the complete use case without workarounds?
|
||||
□ References: Do you have 3-5 referenceable customers in the target segment?
|
||||
□ Repeatability: Can you sell and implement without founder involvement?
|
||||
□ Support: Can you support customers at scale (not just white-glove)?
|
||||
□ Positioning: Is the messaging pragmatist-friendly (ROI, risk reduction) not visionary?
|
||||
□ Competition: Have you defined the competitive set for pragmatist comparison?
|
||||
□ Pricing: Is pricing simple, transparent, and aligned with buyer expectations?
|
||||
```
|
||||
|
||||
### Value Chain Analysis
|
||||
|
||||
Decompose industry activities to find competitive advantage:
|
||||
|
||||
```
|
||||
VALUE CHAIN: [Industry]
|
||||
|
||||
PRIMARY ACTIVITIES:
|
||||
┌─────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
|
||||
│ Inbound │ Operations │ Outbound │ Marketing │ Service │
|
||||
│ Logistics │ │ Logistics │ & Sales │ │
|
||||
├─────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
|
||||
│ Sourcing │ Production │ Distribution │ Branding │ Support │
|
||||
│ Inventory │ Quality │ Delivery │ Pricing │ Maintenance │
|
||||
│ Supplier │ Assembly │ Warehousing │ Channel mgmt │ Returns │
|
||||
│ management │ Testing │ Order mgmt │ Positioning │ Training │
|
||||
└─────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
|
||||
|
||||
SUPPORT ACTIVITIES:
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ Infrastructure: Finance, Legal, Management, Planning │
|
||||
│ Human Resources: Recruiting, Training, Compensation, Culture │
|
||||
│ Technology: R&D, IT systems, Automation, Data analytics │
|
||||
│ Procurement: Vendor selection, Negotiation, Contract management │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Analysis Process:**
|
||||
|
||||
```
|
||||
For each activity:
|
||||
1. Cost: What % of total cost does this activity represent?
|
||||
2. Value: How much does this activity contribute to customer willingness-to-pay?
|
||||
3. Capability: Rate your performance vs competitors (1-5)
|
||||
4. Strategic importance: Is this a source of differentiation? (Yes/No)
|
||||
|
||||
Activity | Cost % | Value Contribution | Capability | Differentiator?
|
||||
---------------------|--------|-------------------|------------|----------------
|
||||
Inbound logistics | 15% | Low | 3/5 | No
|
||||
Operations | 25% | High | 4/5 | Yes
|
||||
Outbound logistics | 10% | Medium | 3/5 | No
|
||||
Marketing & Sales | 30% | High | 2/5 | Needs improvement
|
||||
Service | 20% | High | 5/5 | Yes
|
||||
|
||||
Strategic Implications:
|
||||
- Invest: Operations (current strength + high value) and Service (strength to protect)
|
||||
- Improve: Marketing & Sales (high cost + low capability = drag on growth)
|
||||
- Optimize: Logistics (non-differentiating — minimize cost)
|
||||
```
|
||||
|
||||
**SaaS-Specific Value Chain:**
|
||||
|
||||
```
|
||||
┌────────────┬───────────────┬──────────────┬────────────────┬─────────────┐
|
||||
│ Product │ Customer │ Customer │ Customer │ Expansion │
|
||||
│ Development│ Acquisition │ Onboarding │ Success │ & Retention │
|
||||
├────────────┼───────────────┼──────────────┼────────────────┼─────────────┤
|
||||
│ R&D │ Marketing │ Implementation│ Support │ Upsell │
|
||||
│ Design │ Sales │ Training │ Account mgmt │ Cross-sell │
|
||||
│ QA │ Partnerships │ Migration │ Health scoring │ Renewals │
|
||||
│ Platform │ Growth/PLG │ Integration │ Community │ Advocacy │
|
||||
└────────────┴───────────────┴──────────────┴────────────────┴─────────────┘
|
||||
|
||||
Key insight for SaaS: The majority of LTV is created AFTER the initial sale.
|
||||
Disproportionate investment should go to Onboarding → Success → Expansion.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Strategic Analysis Anti-Patterns
|
||||
|
||||
Common cognitive traps that produce bad strategy. Actively check for these in every analysis:
|
||||
|
||||
| Anti-Pattern | Detection Question | Countermeasure |
|
||||
|---|---|---|
|
||||
| **Confirmation Bias** — Seeking data that supports pre-existing beliefs; ignoring contradictory evidence | "Did I search for disconfirming evidence with equal effort?" | For every key conclusion, explicitly search for the strongest counterargument |
|
||||
| **Anchoring** — First number encountered dominates all later estimates (first source says "$10B market" and final estimate drifts toward $10B) | "Is my final estimate suspiciously close to the first number I found?" | Collect 3+ independent estimates; use both bottom-up and top-down methods; investigate any 2x+ divergence |
|
||||
| **Strategy-by-Analogy** — "Uber did X, so we should do X in healthcare" without testing structural similarity | "What are the 3 most important differences between this situation and the analogy?" | Use analogies to generate hypotheses, never to validate conclusions |
|
||||
| **Missing Causal Chain** — Clear start and desirable end, but no credible mechanism connecting them (Step 1 → ??? → Profit) | "What specifically happens between 'launch' and 'achieve outcome'?" | Every recommendation needs a testable causal chain: A → B → C → D |
|
||||
| **Denominator Neglect** — Citing impressive absolutes while ignoring base rates ("10,000 users!" out of 2M impressions = 0.5%) | "Relative to what?" | Always present metrics as ratios/rates; compare to benchmarks |
|
||||
| **Survivorship Bias** — Deriving strategy from winners only; ignoring that failed companies tried the same thing | "How many companies tried this and failed?" | Seek failure case studies; note success AND failure rates |
|
||||
| **Planning Fallacy** — Timelines assuming everything goes right | "Does this plan require performing better than we ever have?" | Use reference class forecasting; add 30-50% buffer; present best/base/worst timelines |
|
||||
|
||||
---
|
||||
|
||||
## Uncertainty Quantification
|
||||
|
||||
### Expressing Uncertainty
|
||||
|
||||
**For quantitative estimates (market size, revenue, costs):**
|
||||
- Never give a single number. Always give a range: "Market size: $8-12B (base estimate $10B)"
|
||||
- State the confidence interval: "80% confident the market is between $8B and $12B"
|
||||
- Identify the key variable driving the range: "Range is driven primarily by uncertainty in adoption rate (15-25%)"
|
||||
|
||||
**For qualitative assessments:**
|
||||
- Use the calibrated confidence scale consistently:
|
||||
- **Very High (>90%)**: Would be genuinely surprised if wrong. Multiple high-quality sources agree.
|
||||
- **High (70-90%)**: Strong evidence, but plausible alternative interpretations exist.
|
||||
- **Medium (50-70%)**: Balanced evidence. Reasonable people could disagree.
|
||||
- **Low (30-50%)**: More uncertain than certain. Treat as hypothesis, not finding.
|
||||
- **Very Low (<30%)**: Speculative. Useful for scenario planning but not for action.
|
||||
|
||||
### Assumption Tracking
|
||||
|
||||
Every analysis rests on assumptions. Make them explicit:
|
||||
|
||||
```
|
||||
ASSUMPTION REGISTER:
|
||||
|
||||
| # | Assumption | Confidence | Impact if Wrong | Validation Method |
|
||||
|---|-----------|------------|-----------------|-------------------|
|
||||
| 1 | Market grows 15% YoY | High | Changes TAM by +/- 30% | Track quarterly industry reports |
|
||||
| 2 | No new regulation in 12mo | Medium | Could block market entry | Monitor regulatory pipeline |
|
||||
| 3 | Key hire joins by Q2 | Medium | Delays launch 3-6 months | Pipeline status check monthly |
|
||||
| 4 | Competitor does not cut price | Low | Margin compression 10-15% | Track competitor pricing weekly |
|
||||
```
|
||||
|
||||
Flag any assumption rated "Low" that has "High" impact — these are the **strategic landmines** that deserve contingency plans.
|
||||
|
||||
### When to Say "We Don't Know"
|
||||
|
||||
It is better to say "insufficient data to assess" than to fabricate a confident-sounding answer. Specifically:
|
||||
- If fewer than 2 independent sources support a data point, flag it as unverified
|
||||
- If the key variable has a range wider than 3x (e.g., market could be $5B or $15B), call out that the analysis is highly sensitive to this input
|
||||
- If you are extrapolating a trend beyond the data range, state the extrapolation explicitly
|
||||
|
||||
---
|
||||
|
||||
## Industry-Specific Strategic Patterns
|
||||
|
||||
Certain strategic dynamics recur within industry categories. Recognizing these patterns accelerates analysis:
|
||||
|
||||
### Platform / Marketplace Businesses
|
||||
- **Winner-take-most dynamics**: Network effects create power-law outcomes. Market share of #1 player often exceeds #2 + #3 combined.
|
||||
- **Chicken-and-egg problem**: Must solve supply and demand simultaneously. Common solutions: single-player mode, subsidize one side, constrain geography first.
|
||||
- **Multi-homing risk**: If users can easily use multiple platforms, network effects weaken. Strategy must increase switching costs or exclusive value.
|
||||
- **Key metric**: Liquidity (match rate between supply and demand). Revenue follows liquidity, not the reverse.
|
||||
|
||||
### B2B SaaS
|
||||
- **Land-and-expand**: Initial deal size matters less than expansion potential. Net revenue retention >120% can drive growth even at 0 new logos.
|
||||
- **Switching cost lifecycle**: Switching costs increase with integration depth, data accumulation, and workflow embedding. Year 1 churn is always highest.
|
||||
- **Category creation vs. category entry**: Creating a new category requires 3-5x more marketing spend but yields pricing power. Entering an existing category is cheaper but forces competitive positioning.
|
||||
- **Key metric**: Net Revenue Retention (NRR). Above 130% = exceptional. Below 100% = leaky bucket that marketing cannot fill.
|
||||
|
||||
### Consumer / D2C
|
||||
- **Acquisition cost spiral**: As easy-to-reach audiences saturate, CAC rises. Growth requires channel diversification or organic/viral mechanics.
|
||||
- **Brand as moat**: In commoditized categories, brand is the primary differentiation. Brand building requires consistency over years, not campaigns over months.
|
||||
- **Retention curve shape**: If the retention curve flattens (users who stay past day 30 tend to stay indefinitely), invest in onboarding. If it keeps declining, the product has a retention problem, not an acquisition problem.
|
||||
- **Key metric**: Cohort retention at day 30/60/90. Payback period on CAC.
|
||||
|
||||
### Regulated Industries (Healthcare, Finance, Insurance)
|
||||
- **Compliance as moat**: Regulatory requirements (HIPAA, SOC2, PCI-DSS) are expensive to achieve but create durable barriers to entry.
|
||||
- **Sales cycle reality**: Enterprise sales cycles of 6-18 months are normal. Budget accordingly. Premature scaling of sales teams is the #1 killer.
|
||||
- **Build vs. partner**: In heavily regulated industries, partnering with incumbents (who have regulatory relationships) often beats trying to disrupt them directly.
|
||||
- **Key metric**: Sales cycle length, regulatory approval timeline, compliance cost as % of revenue.
|
||||
@@ -781,6 +781,337 @@ default_active = false
|
||||
# Warning shown when user tries to activate
|
||||
activation_warning = "Trading hand runs continuously and consumes tokens. Deactivate when not trading."
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "交易 Hand"
|
||||
description = "自主市场情报与交易引擎——多信号分析、对抗性多空推理、校准置信度评分、严格风控和投资组合分析"
|
||||
category = "数据"
|
||||
|
||||
[i18n.zh.settings.trading_mode]
|
||||
label = "交易模式"
|
||||
description = "交易 Hand 的运行方式——仅分析、模拟交易或实盘交易"
|
||||
|
||||
[i18n.zh.settings.market_focus]
|
||||
label = "市场关注"
|
||||
description = "监控和交易的目标市场"
|
||||
|
||||
[i18n.zh.settings.strategy_style]
|
||||
label = "策略风格"
|
||||
description = "交易时间框架和策略类型"
|
||||
|
||||
[i18n.zh.settings.risk_per_trade]
|
||||
label = "单笔风险"
|
||||
description = "单笔交易允许承受的最大仓位占比"
|
||||
|
||||
[i18n.zh.settings.max_daily_loss]
|
||||
label = "单日最大亏损"
|
||||
description = "触发熔断机制的每日最大允许亏损比例"
|
||||
|
||||
[i18n.zh.settings.analysis_depth]
|
||||
label = "分析深度"
|
||||
description = "每个标的收集和交叉验证的信号数量"
|
||||
|
||||
[i18n.zh.settings.scan_schedule]
|
||||
label = "扫描频率"
|
||||
description = "扫描市场和更新分析的频率"
|
||||
|
||||
[i18n.zh.settings.watchlist]
|
||||
label = "关注列表"
|
||||
description = "要监控的标的代码列表(逗号分隔,股票: AAPL,加密货币: BTC,ETF: SPY)"
|
||||
|
||||
[i18n.zh.settings.initial_capital]
|
||||
label = "初始资金"
|
||||
description = "模拟交易或追踪的起始投资组合金额(美元)"
|
||||
|
||||
[i18n.zh.settings.alpaca_api_key]
|
||||
label = "Alpaca API 密钥"
|
||||
description = "用于实盘/模拟交易的 Alpaca API 密钥(可在 alpaca.markets 免费获取)"
|
||||
|
||||
[i18n.zh.settings.alpaca_secret_key]
|
||||
label = "Alpaca Secret 密钥"
|
||||
description = "Alpaca API 的 Secret 密钥"
|
||||
|
||||
[i18n.zh.settings.approval_mode]
|
||||
label = "审批模式"
|
||||
description = "执行实盘交易前需要用户明确审批——强烈建议开启"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Trading"
|
||||
description = "Motor autónomo de inteligencia de mercado y trading — análisis multi-señal, razonamiento adversarial alcista/bajista, puntuación de confianza calibrada, gestión de riesgo estricta y analítica de cartera"
|
||||
category = "Datos"
|
||||
|
||||
[i18n.es.settings.trading_mode]
|
||||
label = "Modo de trading"
|
||||
description = "Cómo opera el Hand de Trading — solo análisis, trading simulado o trading real"
|
||||
|
||||
[i18n.es.settings.market_focus]
|
||||
label = "Enfoque de mercado"
|
||||
description = "Qué mercados monitorear y operar"
|
||||
|
||||
[i18n.es.settings.strategy_style]
|
||||
label = "Estilo de estrategia"
|
||||
description = "Marco temporal y enfoque de la estrategia de trading"
|
||||
|
||||
[i18n.es.settings.risk_per_trade]
|
||||
label = "Riesgo por operación"
|
||||
description = "Porcentaje máximo de la cartera en riesgo en una sola operación"
|
||||
|
||||
[i18n.es.settings.max_daily_loss]
|
||||
label = "Pérdida diaria máxima"
|
||||
description = "Porcentaje máximo de pérdida diaria de la cartera antes de activar el disyuntor"
|
||||
|
||||
[i18n.es.settings.analysis_depth]
|
||||
label = "Profundidad del análisis"
|
||||
description = "Cuántas señales recopilar y cruzar por activo"
|
||||
|
||||
[i18n.es.settings.scan_schedule]
|
||||
label = "Frecuencia de escaneo"
|
||||
description = "Con qué frecuencia escanear los mercados y actualizar el análisis"
|
||||
|
||||
[i18n.es.settings.watchlist]
|
||||
label = "Lista de seguimiento"
|
||||
description = "Lista de tickers a monitorear separados por comas (acciones: AAPL, cripto: BTC, ETFs: SPY)"
|
||||
|
||||
[i18n.es.settings.initial_capital]
|
||||
label = "Capital inicial"
|
||||
description = "Valor inicial de la cartera para trading simulado o seguimiento (en USD)"
|
||||
|
||||
[i18n.es.settings.alpaca_api_key]
|
||||
label = "Clave API de Alpaca"
|
||||
description = "Clave API de Alpaca para trading real/simulado (obtener gratis en alpaca.markets)"
|
||||
|
||||
[i18n.es.settings.alpaca_secret_key]
|
||||
label = "Clave secreta de Alpaca"
|
||||
description = "Clave secreta de la API de Alpaca"
|
||||
|
||||
[i18n.es.settings.approval_mode]
|
||||
label = "Modo de aprobación"
|
||||
description = "Requerir aprobación explícita del usuario antes de ejecutar cualquier operación real — altamente recomendado"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "トレーディング Hand"
|
||||
description = "自律型マーケットインテリジェンス&トレーディングエンジン——マルチシグナル分析、対立的ブル/ベア推論、キャリブレーション済み信頼度スコアリング、厳格なリスク管理、ポートフォリオ分析"
|
||||
category = "データ"
|
||||
|
||||
[i18n.ja.settings.trading_mode]
|
||||
label = "トレーディングモード"
|
||||
description = "トレーディングHandの動作方式——分析のみ、ペーパートレード、またはライブトレード"
|
||||
|
||||
[i18n.ja.settings.market_focus]
|
||||
label = "マーケットフォーカス"
|
||||
description = "監視・取引する対象市場"
|
||||
|
||||
[i18n.ja.settings.strategy_style]
|
||||
label = "戦略スタイル"
|
||||
description = "取引の時間軸と戦略アプローチ"
|
||||
|
||||
[i18n.ja.settings.risk_per_trade]
|
||||
label = "1トレードあたりのリスク"
|
||||
description = "1回の取引でリスクにさらすポートフォリオの最大割合"
|
||||
|
||||
[i18n.ja.settings.max_daily_loss]
|
||||
label = "1日の最大損失"
|
||||
description = "サーキットブレーカーが作動するまでの1日あたりの最大損失割合"
|
||||
|
||||
[i18n.ja.settings.analysis_depth]
|
||||
label = "分析の深さ"
|
||||
description = "銘柄ごとに収集・クロスリファレンスするシグナルの数"
|
||||
|
||||
[i18n.ja.settings.scan_schedule]
|
||||
label = "スキャンスケジュール"
|
||||
description = "市場スキャンと分析更新の頻度"
|
||||
|
||||
[i18n.ja.settings.watchlist]
|
||||
label = "ウォッチリスト"
|
||||
description = "監視するティッカーのリスト(カンマ区切り、株式: AAPL、暗号通貨: BTC、ETF: SPY)"
|
||||
|
||||
[i18n.ja.settings.initial_capital]
|
||||
label = "初期資金"
|
||||
description = "ペーパートレードまたはトラッキングの開始ポートフォリオ額(USD)"
|
||||
|
||||
[i18n.ja.settings.alpaca_api_key]
|
||||
label = "Alpaca APIキー"
|
||||
description = "ライブ/ペーパートレード用のAlpaca APIキー(alpaca.marketsで無料取得可能)"
|
||||
|
||||
[i18n.ja.settings.alpaca_secret_key]
|
||||
label = "Alpaca Secretキー"
|
||||
description = "Alpaca APIのSecretキー"
|
||||
|
||||
[i18n.ja.settings.approval_mode]
|
||||
label = "承認モード"
|
||||
description = "ライブトレード実行前にユーザーの明示的な承認を必要とする——強く推奨"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand de Trading"
|
||||
description = "Moteur autonome d'intelligence de marché et de trading — analyse multi-signaux, raisonnement adversarial haussier/baissier, score de confiance calibré, gestion stricte des risques et analytique de portefeuille"
|
||||
category = "Données"
|
||||
|
||||
[i18n.fr.settings.trading_mode]
|
||||
label = "Mode de trading"
|
||||
description = "Mode de fonctionnement du Hand de Trading — analyse seule, trading simulé ou trading réel"
|
||||
|
||||
[i18n.fr.settings.market_focus]
|
||||
label = "Focus marché"
|
||||
description = "Quels marchés surveiller et sur lesquels opérer"
|
||||
|
||||
[i18n.fr.settings.strategy_style]
|
||||
label = "Style de stratégie"
|
||||
description = "Horizon temporel et approche de la stratégie de trading"
|
||||
|
||||
[i18n.fr.settings.risk_per_trade]
|
||||
label = "Risque par opération"
|
||||
description = "Pourcentage maximum du portefeuille en risque sur une seule opération"
|
||||
|
||||
[i18n.fr.settings.max_daily_loss]
|
||||
label = "Perte quotidienne maximale"
|
||||
description = "Pourcentage maximum de perte quotidienne du portefeuille avant déclenchement du coupe-circuit"
|
||||
|
||||
[i18n.fr.settings.analysis_depth]
|
||||
label = "Profondeur d'analyse"
|
||||
description = "Nombre de signaux à collecter et recouper par actif"
|
||||
|
||||
[i18n.fr.settings.scan_schedule]
|
||||
label = "Fréquence de scan"
|
||||
description = "Fréquence de scan des marchés et de mise à jour de l'analyse"
|
||||
|
||||
[i18n.fr.settings.watchlist]
|
||||
label = "Liste de surveillance"
|
||||
description = "Liste de tickers à surveiller séparés par des virgules (actions : AAPL, crypto : BTC, ETF : SPY)"
|
||||
|
||||
[i18n.fr.settings.initial_capital]
|
||||
label = "Capital initial"
|
||||
description = "Valeur initiale du portefeuille pour le trading simulé ou le suivi (en USD)"
|
||||
|
||||
[i18n.fr.settings.alpaca_api_key]
|
||||
label = "Clé API Alpaca"
|
||||
description = "Clé API Alpaca pour le trading réel/simulé (obtenir gratuitement sur alpaca.markets)"
|
||||
|
||||
[i18n.fr.settings.alpaca_secret_key]
|
||||
label = "Clé secrète Alpaca"
|
||||
description = "Clé secrète de l'API Alpaca"
|
||||
|
||||
[i18n.fr.settings.approval_mode]
|
||||
label = "Mode d'approbation"
|
||||
description = "Exiger l'approbation explicite de l'utilisateur avant d'exécuter toute opération réelle — fortement recommandé"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Trading-Hand"
|
||||
description = "Autonomer Marktintelligenz- und Trading-Motor — Multi-Signal-Analyse, adversariales Bull/Bear-Reasoning, kalibriertes Konfidenz-Scoring, striktes Risikomanagement und Portfolio-Analytik"
|
||||
category = "Daten"
|
||||
|
||||
[i18n.de.settings.trading_mode]
|
||||
label = "Trading-Modus"
|
||||
description = "Betriebsmodus des Trading-Hand — nur Analyse, simuliertes Trading oder Live-Trading"
|
||||
|
||||
[i18n.de.settings.market_focus]
|
||||
label = "Marktfokus"
|
||||
description = "Welche Märkte überwacht und gehandelt werden"
|
||||
|
||||
[i18n.de.settings.strategy_style]
|
||||
label = "Strategiestil"
|
||||
description = "Zeithorizont und Ansatz der Handelsstrategie"
|
||||
|
||||
[i18n.de.settings.risk_per_trade]
|
||||
label = "Risiko pro Trade"
|
||||
description = "Maximaler Prozentsatz des Portfolios, der bei einem einzelnen Trade riskiert wird"
|
||||
|
||||
[i18n.de.settings.max_daily_loss]
|
||||
label = "Maximaler Tagesverlust"
|
||||
description = "Maximaler täglicher Portfolioverlust in Prozent, bevor der Circuit Breaker auslöst"
|
||||
|
||||
[i18n.de.settings.analysis_depth]
|
||||
label = "Analysetiefe"
|
||||
description = "Anzahl der pro Asset zu sammelnden und gegenzuprüfenden Signale"
|
||||
|
||||
[i18n.de.settings.scan_schedule]
|
||||
label = "Scan-Zeitplan"
|
||||
description = "Wie oft Märkte gescannt und Analysen aktualisiert werden"
|
||||
|
||||
[i18n.de.settings.watchlist]
|
||||
label = "Watchlist"
|
||||
description = "Kommagetrennte Liste der zu überwachenden Ticker (Aktien: AAPL, Krypto: BTC, ETFs: SPY)"
|
||||
|
||||
[i18n.de.settings.initial_capital]
|
||||
label = "Anfangskapital"
|
||||
description = "Anfänglicher Portfoliowert für simuliertes Trading oder Tracking (in USD)"
|
||||
|
||||
[i18n.de.settings.alpaca_api_key]
|
||||
label = "Alpaca API-Schlüssel"
|
||||
description = "Alpaca API-Schlüssel für Live-/Papierhandel (kostenlos auf alpaca.markets erhältlich)"
|
||||
|
||||
[i18n.de.settings.alpaca_secret_key]
|
||||
label = "Alpaca Secret-Schlüssel"
|
||||
description = "Secret-Schlüssel der Alpaca API"
|
||||
|
||||
[i18n.de.settings.approval_mode]
|
||||
label = "Genehmigungsmodus"
|
||||
description = "Ausdrückliche Benutzergenehmigung vor der Ausführung von Live-Trades erforderlich — dringend empfohlen"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "트레이딩 Hand"
|
||||
description = "자율 시장 인텔리전스 및 트레이딩 엔진 — 다중 신호 분석, 대립적 매수/매도 추론, 보정된 신뢰도 평가, 엄격한 리스크 관리 및 포트폴리오 분석"
|
||||
category = "데이터"
|
||||
|
||||
[i18n.ko.settings.trading_mode]
|
||||
label = "트레이딩 모드"
|
||||
description = "트레이딩 Hand의 운영 방식 — 분석 전용, 모의 거래 또는 실거래"
|
||||
|
||||
[i18n.ko.settings.market_focus]
|
||||
label = "시장 관심"
|
||||
description = "모니터링 및 거래할 대상 시장"
|
||||
|
||||
[i18n.ko.settings.strategy_style]
|
||||
label = "전략 스타일"
|
||||
description = "거래 시간 프레임 및 전략 유형"
|
||||
|
||||
[i18n.ko.settings.risk_per_trade]
|
||||
label = "거래당 리스크"
|
||||
description = "단일 거래에서 허용되는 최대 포트폴리오 비율"
|
||||
|
||||
[i18n.ko.settings.max_daily_loss]
|
||||
label = "일일 최대 손실"
|
||||
description = "서킷 브레이커 발동 전 허용되는 일일 최대 손실 비율"
|
||||
|
||||
[i18n.ko.settings.analysis_depth]
|
||||
label = "분석 깊이"
|
||||
description = "자산별 수집 및 교차 검증할 신호 수"
|
||||
|
||||
[i18n.ko.settings.scan_schedule]
|
||||
label = "스캔 일정"
|
||||
description = "시장 스캔 및 분석 업데이트 주기"
|
||||
|
||||
[i18n.ko.settings.watchlist]
|
||||
label = "관심 목록"
|
||||
description = "모니터링할 종목 코드 목록 (쉼표로 구분, 주식: AAPL, 암호화폐: BTC, ETF: SPY)"
|
||||
|
||||
[i18n.ko.settings.initial_capital]
|
||||
label = "초기 자본"
|
||||
description = "모의 거래 또는 추적을 위한 시작 포트폴리오 금액 (USD)"
|
||||
|
||||
[i18n.ko.settings.alpaca_api_key]
|
||||
label = "Alpaca API 키"
|
||||
description = "실거래/모의 거래용 Alpaca API 키 (alpaca.markets에서 무료 발급)"
|
||||
|
||||
[i18n.ko.settings.alpaca_secret_key]
|
||||
label = "Alpaca 시크릿 키"
|
||||
description = "Alpaca API 시크릿 키"
|
||||
|
||||
[i18n.ko.settings.approval_mode]
|
||||
label = "승인 모드"
|
||||
description = "실거래 실행 전 사용자의 명시적 승인 필요 — 강력히 권장"
|
||||
@@ -526,6 +526,313 @@ frequency = "hourly"
|
||||
token_consumption = "medium"
|
||||
default_active = false
|
||||
|
||||
# ─── Internationalization (optional) ─────────────────────────────────────────
|
||||
# All i18n sections are optional. Without them, the English values above are used.
|
||||
# To localize, add [i18n.LANG] sections (e.g. zh, ja, ko, es, fr, de).
|
||||
# Settings translations are also optional — omit to keep English labels.
|
||||
|
||||
# ─── Chinese (简体中文) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.zh]
|
||||
name = "Twitter Hand"
|
||||
description = "自主 Twitter/X 管理——内容创作、定时发布、互动管理和效果追踪"
|
||||
category = "通信"
|
||||
|
||||
[i18n.zh.settings.twitter_bearer_token]
|
||||
label = "Twitter Bearer Token"
|
||||
description = "Twitter/X 开发者平台的 Bearer Token,所有 Twitter API 操作均需此凭证。"
|
||||
|
||||
[i18n.zh.settings.twitter_style]
|
||||
label = "内容风格"
|
||||
description = "推文的语气和风格"
|
||||
|
||||
[i18n.zh.settings.post_frequency]
|
||||
label = "发布频率"
|
||||
description = "创建和发布内容的频率"
|
||||
|
||||
[i18n.zh.settings.auto_reply]
|
||||
label = "自动回复"
|
||||
description = "自动回复提及和相关对话"
|
||||
|
||||
[i18n.zh.settings.auto_like]
|
||||
label = "自动点赞"
|
||||
description = "自动为人脉网络中的推文和相关内容点赞"
|
||||
|
||||
[i18n.zh.settings.content_topics]
|
||||
label = "内容主题"
|
||||
description = "要创作内容的主题(逗号分隔,例如 AI、创业、效率提升)"
|
||||
|
||||
[i18n.zh.settings.brand_voice]
|
||||
label = "品牌调性"
|
||||
description = "描述你的独特风格(例如"用幽默简化复杂技术的创业者")"
|
||||
|
||||
[i18n.zh.settings.thread_mode]
|
||||
label = "推文串模式"
|
||||
description = "在内容组合中加入推文串(多条推文组成的故事)"
|
||||
|
||||
[i18n.zh.settings.content_queue_size]
|
||||
label = "内容队列大小"
|
||||
description = "待发队列中保持的推文数量"
|
||||
|
||||
[i18n.zh.settings.engagement_hours]
|
||||
label = "互动时段"
|
||||
description = "检查提及和互动的时间段"
|
||||
|
||||
[i18n.zh.settings.approval_mode]
|
||||
label = "审批模式"
|
||||
description = "将推文写入队列等待审核,而非直接发布"
|
||||
|
||||
# ─── Spanish (Español) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.es]
|
||||
name = "Hand de Twitter"
|
||||
description = "Gestor autónomo de Twitter/X — creación de contenido, publicación programada, interacciones y seguimiento de rendimiento"
|
||||
category = "Comunicación"
|
||||
|
||||
[i18n.es.settings.twitter_bearer_token]
|
||||
label = "Token Bearer de Twitter"
|
||||
description = "Token Bearer del Portal de Desarrolladores de Twitter/X. Requerido para todas las operaciones de la API de Twitter."
|
||||
|
||||
[i18n.es.settings.twitter_style]
|
||||
label = "Estilo de contenido"
|
||||
description = "Voz y tono para tus tweets"
|
||||
|
||||
[i18n.es.settings.post_frequency]
|
||||
label = "Frecuencia de publicación"
|
||||
description = "Con qué frecuencia crear y publicar contenido"
|
||||
|
||||
[i18n.es.settings.auto_reply]
|
||||
label = "Respuesta automática"
|
||||
description = "Responder automáticamente a menciones y conversaciones relevantes"
|
||||
|
||||
[i18n.es.settings.auto_like]
|
||||
label = "Me gusta automático"
|
||||
description = "Dar me gusta automáticamente a tweets de tu red y contenido relevante"
|
||||
|
||||
[i18n.es.settings.content_topics]
|
||||
label = "Temas de contenido"
|
||||
description = "Temas sobre los que crear contenido (separados por comas, ej. IA, startups, productividad)"
|
||||
|
||||
[i18n.es.settings.brand_voice]
|
||||
label = "Voz de marca"
|
||||
description = "Describe tu voz única (ej. 'fundador sarcástico que simplifica la tecnología compleja')"
|
||||
|
||||
[i18n.es.settings.thread_mode]
|
||||
label = "Modo de hilos"
|
||||
description = "Incluir hilos de tweets (historias de múltiples tweets) en la mezcla de contenido"
|
||||
|
||||
[i18n.es.settings.content_queue_size]
|
||||
label = "Tamaño de la cola de contenido"
|
||||
description = "Número de tweets a mantener en la cola preparada"
|
||||
|
||||
[i18n.es.settings.engagement_hours]
|
||||
label = "Horario de interacción"
|
||||
description = "Cuándo verificar menciones e interactuar"
|
||||
|
||||
[i18n.es.settings.approval_mode]
|
||||
label = "Modo de aprobación"
|
||||
description = "Escribir los tweets en un archivo de cola para revisión en lugar de publicarlos directamente"
|
||||
|
||||
# ─── Japanese (日本語) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ja]
|
||||
name = "Twitter Hand"
|
||||
description = "自律型Twitter/Xマネージャー——コンテンツ作成、スケジュール投稿、エンゲージメント管理、パフォーマンス追跡"
|
||||
category = "コミュニケーション"
|
||||
|
||||
[i18n.ja.settings.twitter_bearer_token]
|
||||
label = "Twitter Bearerトークン"
|
||||
description = "Twitter/X開発者ポータルのBearerトークン。すべてのTwitter API操作に必要です。"
|
||||
|
||||
[i18n.ja.settings.twitter_style]
|
||||
label = "コンテンツスタイル"
|
||||
description = "ツイートの語調とスタイル"
|
||||
|
||||
[i18n.ja.settings.post_frequency]
|
||||
label = "投稿頻度"
|
||||
description = "コンテンツの作成・投稿の頻度"
|
||||
|
||||
[i18n.ja.settings.auto_reply]
|
||||
label = "自動返信"
|
||||
description = "メンションや関連する会話に自動で返信する"
|
||||
|
||||
[i18n.ja.settings.auto_like]
|
||||
label = "自動いいね"
|
||||
description = "ネットワーク内のツイートや関連コンテンツに自動でいいねする"
|
||||
|
||||
[i18n.ja.settings.content_topics]
|
||||
label = "コンテンツトピック"
|
||||
description = "作成するコンテンツのトピック(カンマ区切り、例: AI、スタートアップ、生産性)"
|
||||
|
||||
[i18n.ja.settings.brand_voice]
|
||||
label = "ブランドボイス"
|
||||
description = "あなた独自の語り口を記述(例:「複雑なテクノロジーをわかりやすく伝える皮肉屋の起業家」)"
|
||||
|
||||
[i18n.ja.settings.thread_mode]
|
||||
label = "スレッドモード"
|
||||
description = "コンテンツミックスにツイートスレッド(複数ツイートで構成するストーリー)を含める"
|
||||
|
||||
[i18n.ja.settings.content_queue_size]
|
||||
label = "コンテンツキューサイズ"
|
||||
description = "準備キューに保持するツイートの数"
|
||||
|
||||
[i18n.ja.settings.engagement_hours]
|
||||
label = "エンゲージメント時間帯"
|
||||
description = "メンションの確認とエンゲージメントを行う時間帯"
|
||||
|
||||
[i18n.ja.settings.approval_mode]
|
||||
label = "承認モード"
|
||||
description = "ツイートを直接投稿せず、レビュー用のキューファイルに書き出す"
|
||||
|
||||
# ─── French (Français) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.fr]
|
||||
name = "Hand Twitter"
|
||||
description = "Gestionnaire Twitter/X autonome — création de contenu, publication programmée, interactions et suivi des performances"
|
||||
category = "Communication"
|
||||
|
||||
[i18n.fr.settings.twitter_bearer_token]
|
||||
label = "Jeton Bearer Twitter"
|
||||
description = "Jeton Bearer du Portail Développeurs Twitter/X. Requis pour toutes les opérations de l'API Twitter."
|
||||
|
||||
[i18n.fr.settings.twitter_style]
|
||||
label = "Style de contenu"
|
||||
description = "Ton et style pour vos tweets"
|
||||
|
||||
[i18n.fr.settings.post_frequency]
|
||||
label = "Fréquence de publication"
|
||||
description = "Fréquence de création et de publication de contenu"
|
||||
|
||||
[i18n.fr.settings.auto_reply]
|
||||
label = "Réponse automatique"
|
||||
description = "Répondre automatiquement aux mentions et conversations pertinentes"
|
||||
|
||||
[i18n.fr.settings.auto_like]
|
||||
label = "Like automatique"
|
||||
description = "Aimer automatiquement les tweets de votre réseau et le contenu pertinent"
|
||||
|
||||
[i18n.fr.settings.content_topics]
|
||||
label = "Sujets de contenu"
|
||||
description = "Sujets sur lesquels créer du contenu (séparés par des virgules, ex. IA, startups, productivité)"
|
||||
|
||||
[i18n.fr.settings.brand_voice]
|
||||
label = "Voix de marque"
|
||||
description = "Décrivez votre voix unique (ex. 'fondateur sarcastique qui simplifie la technologie complexe')"
|
||||
|
||||
[i18n.fr.settings.thread_mode]
|
||||
label = "Mode fil de discussion"
|
||||
description = "Inclure des fils de tweets (histoires à plusieurs tweets) dans le mix de contenu"
|
||||
|
||||
[i18n.fr.settings.content_queue_size]
|
||||
label = "Taille de la file de contenu"
|
||||
description = "Nombre de tweets à maintenir dans la file d'attente préparée"
|
||||
|
||||
[i18n.fr.settings.engagement_hours]
|
||||
label = "Heures d'engagement"
|
||||
description = "Quand vérifier les mentions et interagir"
|
||||
|
||||
[i18n.fr.settings.approval_mode]
|
||||
label = "Mode d'approbation"
|
||||
description = "Écrire les tweets dans un fichier d'attente pour révision au lieu de les publier directement"
|
||||
|
||||
# ─── German (Deutsch) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.de]
|
||||
name = "Twitter-Hand"
|
||||
description = "Autonomer Twitter/X-Manager — Content-Erstellung, geplante Veröffentlichung, Engagement-Management und Performance-Tracking"
|
||||
category = "Kommunikation"
|
||||
|
||||
[i18n.de.settings.twitter_bearer_token]
|
||||
label = "Twitter Bearer-Token"
|
||||
description = "Bearer-Token vom Twitter/X-Entwicklerportal. Erforderlich für alle Twitter-API-Operationen."
|
||||
|
||||
[i18n.de.settings.twitter_style]
|
||||
label = "Inhaltsstil"
|
||||
description = "Ton und Stil für Ihre Tweets"
|
||||
|
||||
[i18n.de.settings.post_frequency]
|
||||
label = "Veröffentlichungshäufigkeit"
|
||||
description = "Wie oft Inhalte erstellt und veröffentlicht werden"
|
||||
|
||||
[i18n.de.settings.auto_reply]
|
||||
label = "Automatische Antwort"
|
||||
description = "Automatisch auf Erwähnungen und relevante Gespräche antworten"
|
||||
|
||||
[i18n.de.settings.auto_like]
|
||||
label = "Automatisches Like"
|
||||
description = "Tweets im Netzwerk und relevante Inhalte automatisch liken"
|
||||
|
||||
[i18n.de.settings.content_topics]
|
||||
label = "Inhaltsthemen"
|
||||
description = "Themen für die Content-Erstellung (kommagetrennt, z.B. KI, Startups, Produktivität)"
|
||||
|
||||
[i18n.de.settings.brand_voice]
|
||||
label = "Markenstimme"
|
||||
description = "Beschreiben Sie Ihre einzigartige Stimme (z.B. 'sarkastischer Gründer, der komplexe Technologie vereinfacht')"
|
||||
|
||||
[i18n.de.settings.thread_mode]
|
||||
label = "Thread-Modus"
|
||||
description = "Tweet-Threads (mehrteilige Tweet-Geschichten) in den Content-Mix aufnehmen"
|
||||
|
||||
[i18n.de.settings.content_queue_size]
|
||||
label = "Größe der Content-Warteschlange"
|
||||
description = "Anzahl der Tweets in der vorbereiteten Warteschlange"
|
||||
|
||||
[i18n.de.settings.engagement_hours]
|
||||
label = "Engagement-Zeiten"
|
||||
description = "Wann Erwähnungen geprüft und interagiert werden soll"
|
||||
|
||||
[i18n.de.settings.approval_mode]
|
||||
label = "Genehmigungsmodus"
|
||||
description = "Tweets in eine Warteschlangendatei zur Überprüfung schreiben, anstatt sie direkt zu veröffentlichen"
|
||||
|
||||
# ─── Korean (한국어) ────────────────────────────────────────────────────
|
||||
|
||||
[i18n.ko]
|
||||
name = "Twitter Hand"
|
||||
description = "자율 Twitter/X 관리 — 콘텐츠 제작, 예약 게시, 소통 관리 및 성과 추적"
|
||||
category = "커뮤니케이션"
|
||||
|
||||
[i18n.ko.settings.twitter_bearer_token]
|
||||
label = "Twitter Bearer 토큰"
|
||||
description = "Twitter/X 개발자 포털의 Bearer 토큰. 모든 Twitter API 작업에 필수."
|
||||
|
||||
[i18n.ko.settings.twitter_style]
|
||||
label = "콘텐츠 스타일"
|
||||
description = "트윗의 어조와 스타일"
|
||||
|
||||
[i18n.ko.settings.post_frequency]
|
||||
label = "게시 빈도"
|
||||
description = "콘텐츠를 작성하고 게시하는 주기"
|
||||
|
||||
[i18n.ko.settings.auto_reply]
|
||||
label = "자동 답글"
|
||||
description = "멘션 및 관련 대화에 자동으로 답글 작성"
|
||||
|
||||
[i18n.ko.settings.auto_like]
|
||||
label = "자동 좋아요"
|
||||
description = "네트워크 내 트윗 및 관련 콘텐츠에 자동으로 좋아요"
|
||||
|
||||
[i18n.ko.settings.content_topics]
|
||||
label = "콘텐츠 주제"
|
||||
description = "콘텐츠를 작성할 주제 (쉼표로 구분, 예: AI, 스타트업, 생산성)"
|
||||
|
||||
[i18n.ko.settings.brand_voice]
|
||||
label = "브랜드 보이스"
|
||||
description = "고유한 스타일을 설명 (예: '복잡한 기술을 쉽게 풀어내는 유머러스한 창업자')"
|
||||
|
||||
[i18n.ko.settings.thread_mode]
|
||||
label = "스레드 모드"
|
||||
description = "콘텐츠 구성에 트윗 스레드 (다중 트윗 스토리) 포함"
|
||||
|
||||
[i18n.ko.settings.content_queue_size]
|
||||
label = "콘텐츠 대기열 크기"
|
||||
description = "준비 대기열에 유지할 트윗 수"
|
||||
|
||||
[i18n.ko.settings.engagement_hours]
|
||||
label = "소통 시간대"
|
||||
description = "멘션 확인 및 소통 활동을 수행하는 시간대"
|
||||
|
||||
[i18n.ko.settings.approval_mode]
|
||||
label = "승인 모드"
|
||||
description = "트윗을 직접 게시하지 않고 대기열 파일에 기록하여 검토"
|
||||
@@ -226,6 +226,72 @@ Do NOT auto-like:
|
||||
|
||||
---
|
||||
|
||||
## Advanced Engagement Patterns
|
||||
|
||||
### Quote Tweet vs Reply vs Retweet
|
||||
|
||||
Choosing the right interaction type determines whether you gain visibility or waste it.
|
||||
|
||||
**Use a Quote Tweet when**:
|
||||
- You have a distinct take or added context (not just "this!")
|
||||
- The original tweet has high impressions and you want to draft off its reach
|
||||
- You are crediting someone while adding your own insight for your audience
|
||||
- The original author has a similar or larger following (exposes you to their audience)
|
||||
|
||||
**Use a Reply when**:
|
||||
- You want to build a direct relationship with the author
|
||||
- Your comment only makes sense in context of the original
|
||||
- The original author has a much larger following (replies show on their thread, giving you visibility without looking self-promotional)
|
||||
- You are answering a question or adding a correction
|
||||
|
||||
**Use a plain Retweet when**:
|
||||
- The original says everything perfectly and you have nothing to add
|
||||
- You want to signal-boost a community member, customer, or partner
|
||||
- The content is time-sensitive (breaking news, event announcements)
|
||||
|
||||
**Avoid**:
|
||||
- Quote tweeting with only emojis or "this" -- adds no value, looks lazy
|
||||
- Quote tweeting someone with fewer followers just to dunk -- punching down
|
||||
- Retweeting more than 3-4 times per day -- dilutes your original content ratio
|
||||
|
||||
### Thread Repurposing
|
||||
|
||||
A thread that performed well contains 5-7 standalone content pieces. Extract them over the following week to maximize ROI.
|
||||
|
||||
**Process**:
|
||||
1. Day 0 (original): Post the full thread
|
||||
2. Day 2: Pull the single most quotable tweet from the thread. Post it standalone with slightly different wording. No link back to the thread
|
||||
3. Day 4: Turn a data point or example from the thread into a graphic or screenshot tweet
|
||||
4. Day 6: Post the thread's core thesis as a hot take (one tweet, punchy)
|
||||
5. Day 8+: If engagement stayed strong, post a "Part 2" thread that goes deeper on whichever tweet in the original got the most replies
|
||||
|
||||
**Rules**:
|
||||
- Change the wording each time -- copy-pasting feels like spam to followers who saw the original
|
||||
- Space extractions at least 48 hours apart
|
||||
- Stop if any extraction underperforms significantly -- the topic is tapped out
|
||||
- Never repurpose a thread that got low engagement; the content did not resonate
|
||||
|
||||
### Trending Topic Participation
|
||||
|
||||
**When to participate**:
|
||||
- The trend directly intersects one of your content pillars
|
||||
- You have a genuine, informed perspective (not a generic reaction)
|
||||
- The trend is still rising (check the "Trending" tab; if it has been trending for >12 hours, you are late)
|
||||
- The tone of the trend matches your brand voice
|
||||
|
||||
**When to avoid**:
|
||||
- Tragedy, disaster, or crisis events -- opportunistic posting destroys trust
|
||||
- Highly polarized political or social debates outside your expertise
|
||||
- Trends driven by outrage mobs -- associating your brand is high-risk, low-reward
|
||||
- You would need to force-fit your product or message into the trend
|
||||
|
||||
**Execution**:
|
||||
- Lead with your actual insight, not the hashtag. The hashtag goes at the end or is omitted entirely if the topic keyword is in your text
|
||||
- Be early or be different. If 50 people have already made the same joke, skip it
|
||||
- Tie back to your pillar: "Trend X is exactly why [your pillar topic] matters more than ever"
|
||||
|
||||
---
|
||||
|
||||
## Content Calendar Template
|
||||
|
||||
```
|
||||
@@ -254,6 +320,169 @@ Friday:
|
||||
|
||||
---
|
||||
|
||||
## Worked Examples
|
||||
|
||||
### Example 1: Product Launch Twitter Campaign (1-Week Plan)
|
||||
|
||||
**Context**: A dev tools startup is launching "FastDB," an open-source embedded database. The account has 2,400 followers, mostly backend engineers.
|
||||
|
||||
**Pre-launch (3 days before)**:
|
||||
- Seed curiosity without revealing the product name
|
||||
- Engage heavily in database-related threads to increase profile visits before launch
|
||||
|
||||
**Day 1 (Monday) -- Teaser**:
|
||||
```
|
||||
We've been heads-down for 8 months building something
|
||||
we think embedded databases have been missing.
|
||||
|
||||
Shipping it open-source this Thursday.
|
||||
|
||||
More soon.
|
||||
```
|
||||
Purpose: Create anticipation. No hashtags, no links. Let curiosity drive profile visits.
|
||||
|
||||
**Day 2 (Tuesday) -- Problem framing**:
|
||||
```
|
||||
SQLite is incredible for what it does.
|
||||
|
||||
But if you need concurrent writes, ACID transactions,
|
||||
AND sub-millisecond reads in the same embedded DB...
|
||||
your options get thin fast.
|
||||
|
||||
We've been living in that gap. Fix incoming Thursday.
|
||||
```
|
||||
Purpose: Define the problem space. People who feel this pain will follow for the reveal.
|
||||
|
||||
**Day 3 (Wednesday) -- Social proof / build-up**:
|
||||
```
|
||||
Shipped our embedded DB to 12 beta testers last month.
|
||||
|
||||
Results so far:
|
||||
- 4.2x faster concurrent writes vs SQLite WAL mode
|
||||
- Zero-config replication
|
||||
- Single static binary, 3.8 MB
|
||||
|
||||
One more day.
|
||||
```
|
||||
Purpose: Concrete numbers build credibility. "One more day" maintains tension.
|
||||
|
||||
**Day 4 (Thursday) -- Launch day thread** (6-tweet thread):
|
||||
```
|
||||
1/6 [HOOK]: Introducing FastDB -- embedded DB for concurrent-write-heavy
|
||||
workloads. Open source. Single binary. Here's why we built it:
|
||||
2/6 [PROBLEM]: SQLite = single-writer. Fine for reads, hits a wall on
|
||||
write-heavy apps (event logging, IoT, realtime sync). FastDB uses
|
||||
MVCC -- writers never block readers, readers never block writers.
|
||||
3/6 [PROOF]: Benchmarks (M2 Mac, 8 threads): concurrent writes 51K ops/s
|
||||
vs SQLite WAL 12K ops/s. Point reads on par at ~900K ops/s.
|
||||
4/6 [ONBOARD]: Getting started: `cargo add fastdb` then 3 lines of code.
|
||||
Full SQLite-compatible query layer coming in v0.2.
|
||||
5/6 [ROADMAP]: v0.1 ships ACID transactions, built-in replication, crash
|
||||
recovery, zero deps beyond libc. v0.2: SQL layer, S3 cold storage.
|
||||
6/6 [CTA]: Star the repo: github.com/example/fastdb -- open issues, roast
|
||||
the benchmarks, tell us what's missing.
|
||||
```
|
||||
Key structural choices: tweet 1 is a standalone hook, tweet 3 has hard numbers, tweet 6 ends with a specific ask (not just "check it out").
|
||||
|
||||
**Day 4 afternoon** -- Post a standalone tweet answering the most common reply question publicly (drives docs traffic). **Day 5 (Friday)** -- Reply to every substantive comment. Templates for common reactions:
|
||||
- "How is this different from X?" -> Concrete comparison, link to docs
|
||||
- "Benchmarks look suspicious" -> Link the reproduction steps, invite them to run it
|
||||
- "Will you support [feature]?" -> Link the tracking issue
|
||||
|
||||
**Day 6-7 (Weekend)** -- Repurpose: extract the benchmark tweet as a standalone with a chart image; post a "5 things I learned launching an open-source DB" reflection thread.
|
||||
|
||||
### Example 2: Building Thought Leadership from Scratch (Month 1)
|
||||
|
||||
**Context**: An individual ML engineer with 180 followers wants to become a recognized voice in applied machine learning. No existing audience. No viral content history.
|
||||
|
||||
**Core principle for month 1**: Do not broadcast. Contribute. Your first 500 followers come from being consistently useful in other people's threads, not from your own tweets.
|
||||
|
||||
**Week 1 -- Comment-first growth**:
|
||||
- Post 0 original tweets
|
||||
- Find 10 accounts in your niche with 5K-50K followers who post regularly
|
||||
- Reply to 5-8 of their tweets per day with substantive comments (not "great post!")
|
||||
- Goal: Get 3-5 of those authors to like or reply to your comments by end of week
|
||||
|
||||
**What a good reply looks like**:
|
||||
```
|
||||
Original tweet: "Fine-tuning LLMs is overrated. Most use cases
|
||||
are better served by good prompting + RAG."
|
||||
|
||||
Bad reply: "Agreed!"
|
||||
|
||||
Good reply: "Mostly agree, but there's a middle ground --
|
||||
LoRA fine-tuning on 500 domain-specific examples
|
||||
consistently beats RAG for structured extraction tasks.
|
||||
|
||||
We saw 23% higher F1 on invoice parsing after a 2-hour
|
||||
fine-tune vs our best RAG setup.
|
||||
|
||||
RAG still wins for open-domain QA though."
|
||||
```
|
||||
This reply adds data, shows experience, and invites further discussion. People reading the thread see your expertise and check your profile.
|
||||
|
||||
**Week 2 -- First original content**:
|
||||
- Continue the reply strategy (5/day minimum)
|
||||
- Post 2-3 original tweets. Keep them observational, not promotional:
|
||||
```
|
||||
Something I've noticed after fine-tuning 30+ models
|
||||
this year:
|
||||
|
||||
The quality of your eval set matters 10x more than
|
||||
the size of your training set.
|
||||
|
||||
50 carefully labeled examples with clear edge cases
|
||||
beats 5000 noisy scraped examples every time.
|
||||
```
|
||||
- Post 1 "ask the audience" tweet to start conversations:
|
||||
```
|
||||
ML engineers: what's the most counterintuitive lesson
|
||||
you've learned about deploying models to production?
|
||||
|
||||
I'll start: the model is almost never the bottleneck.
|
||||
Data pipelines are.
|
||||
```
|
||||
|
||||
**Week 3 -- First thread** (5-tweet authority thread):
|
||||
```
|
||||
1/5 [HOOK]: I've deployed 12 ML models to production this year. The ones
|
||||
that worked all had one thing in common. It wasn't the architecture.
|
||||
2/5 [THESIS]: Every success had a tight feedback loop -- predictions
|
||||
validated by a human within 24 hours, not "we'll evaluate next quarter."
|
||||
3/5 [EVIDENCE]: Model A (invoice classifier): accountants flagged errors
|
||||
same-day, retrained weekly, 84% -> 97% in 6 weeks. Model B (churn
|
||||
predictor): sales ignored outputs, no feedback 3 months, drifted to
|
||||
coin-flip accuracy.
|
||||
4/5 [FRAMEWORK]: The pattern: (1) deploy with human-in-the-loop review,
|
||||
(2) log every correction, (3) retrain on corrections every 1-2 weeks,
|
||||
(4) remove human review once accuracy stabilizes.
|
||||
5/5 [CTA]: If you're skipping the feedback loop, you're building on sand.
|
||||
What's your experience?
|
||||
```
|
||||
Notice the structure: personal credibility in tweet 1, a clear thesis in tweet 2, contrasting real examples in tweet 3, an actionable takeaway in tweet 4, and a discussion prompt in tweet 5.
|
||||
|
||||
**Week 4 -- Establish rhythm**:
|
||||
- Settle into a sustainable cadence: 1 thread/week, 1-2 standalone tweets/day, 5+ replies/day
|
||||
- Review metrics from week 2-3 content to identify which topics resonated
|
||||
- Double down on the topic that got the most replies (not likes -- replies indicate deeper engagement)
|
||||
|
||||
**Month 1 milestones**:
|
||||
| Metric | Target | Why it matters |
|
||||
|--------|--------|----------------|
|
||||
| Followers | 350-500 | 2-3x growth signals the approach is working |
|
||||
| Avg impressions per tweet | 800-2000 | Shows the algorithm is distributing your content |
|
||||
| Replies received per original tweet | 3-5 | People are engaging, not just scrolling past |
|
||||
| Mutual follows from target accounts | 5-10 | Your niche peers are noticing you |
|
||||
| Profile visits / week | 200+ | Your replies are driving curiosity |
|
||||
|
||||
**What to avoid in month 1**:
|
||||
- Posting 10 tweets/day hoping something sticks -- looks desperate, exhausts your ideas
|
||||
- Buying followers or using engagement pods -- Twitter's algorithm detects and penalizes this
|
||||
- Talking about yourself or your product -- earn attention through insight first
|
||||
- Getting discouraged by low numbers -- 180 to 400 followers in a month is strong growth
|
||||
|
||||
---
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
### Key Metrics
|
||||
|
||||
Reference in new issue
Block a user