workflow-ai 1.0.40 → 1.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-templates/CLAUDE.md.tpl +10 -1
- package/agent-templates/QWEN.md.tpl +18 -1
- package/package.json +3 -1
- package/src/cli.mjs +79 -1
- package/src/global-dir.mjs +90 -0
- package/src/init.mjs +15 -30
- package/src/junction-manager.mjs +184 -0
- package/src/runner.mjs +26 -7
- package/src/scripts/move-to-review.js +5 -1
- package/src/skills/coach/SKILL.md +12 -2
- package/src/skills/coach/workflows/analyze.md +12 -0
- package/src/skills/create-plan/SKILL.md +9 -0
- package/src/skills/decompose-gaps/SKILL.md +6 -0
- package/src/skills/decompose-plan/SKILL.md +52 -1
- package/src/skills/deep-research/README.md +50 -0
- package/src/skills/deep-research/SKILL.md +148 -0
- package/src/skills/deep-research/algorithms/source-scoring.md +63 -0
- package/src/skills/deep-research/algorithms/synthesis.md +67 -0
- package/src/skills/deep-research/knowledge/data-validation.md +44 -0
- package/src/skills/deep-research/knowledge/research-methodology.md +54 -0
- package/src/skills/deep-research/knowledge/source-evaluation.md +33 -0
- package/src/skills/deep-research/scripts/perplexity-research.js +315 -0
- package/src/skills/deep-research/templates/brief-summary.md +25 -0
- package/src/skills/deep-research/templates/research-report.md +76 -0
- package/src/skills/deep-research/workflows/benchmark.md +56 -0
- package/src/skills/deep-research/workflows/competitor.md +63 -0
- package/src/skills/deep-research/workflows/custom.md +45 -0
- package/src/skills/deep-research/workflows/market.md +64 -0
- package/src/skills/deep-research/workflows/technology.md +52 -0
- package/src/skills/deep-research/workflows/trend.md +51 -0
- package/src/skills/execute-task/SKILL.md +48 -2
- package/src/skills/review-result/SKILL.md +329 -285
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* perplexity-research.js — обёртка для вызова Perplexity через kilo proxy без tool use.
|
|
5
|
+
*
|
|
6
|
+
* Проблема: kilo CLI всегда отправляет tool definitions → Perplexity через OpenRouter
|
|
7
|
+
* не поддерживает tool use и возвращает ошибку.
|
|
8
|
+
*
|
|
9
|
+
* Решение: вызываем OpenRouter API через kilo proxy напрямую (без tools),
|
|
10
|
+
* получаем текстовый ответ и выводим в stdout.
|
|
11
|
+
*
|
|
12
|
+
* Использование:
|
|
13
|
+
* node perplexity-research.js "тема исследования"
|
|
14
|
+
* node perplexity-research.js --model perplexity/sonar "тема"
|
|
15
|
+
* node perplexity-research.js --system "Ты исследователь..." "тема"
|
|
16
|
+
*
|
|
17
|
+
* Результат (markdown) выводится в stdout.
|
|
18
|
+
* Прогресс и ошибки — в stderr.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import fs from 'fs';
|
|
22
|
+
import path from 'path';
|
|
23
|
+
import http from 'http';
|
|
24
|
+
import https from 'https';
|
|
25
|
+
import { findProjectRoot } from '../../../lib/find-root.mjs';
|
|
26
|
+
import { createLogger } from '../../../lib/logger.mjs';
|
|
27
|
+
|
|
28
|
+
const logger = createLogger();
|
|
29
|
+
|
|
30
|
+
const AUTH_FILE = path.join(
|
|
31
|
+
process.env.HOME || process.env.USERPROFILE,
|
|
32
|
+
'.local', 'share', 'kilo', 'auth.json'
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const API_URL = 'https://api.kilo.ai/api/openrouter/chat/completions';
|
|
36
|
+
const DEFAULT_MODEL = 'perplexity/sonar-deep-research';
|
|
37
|
+
|
|
38
|
+
const DEFAULT_SYSTEM_PROMPT = `Ты — опытный исследователь-аналитик. Проводи глубокие исследования по заданным темам.
|
|
39
|
+
|
|
40
|
+
Принципы:
|
|
41
|
+
- Каждый факт подкреплён ссылкой на источник. Нет источника = нет факта.
|
|
42
|
+
- Ключевые данные подтверждай минимум 2 независимыми источниками. Если не удалось — помечай [SINGLE SOURCE].
|
|
43
|
+
- Помечай уровень уверенности: [HIGH], [MEDIUM], [LOW].
|
|
44
|
+
- Всегда указывай дату данных.
|
|
45
|
+
- Отделяй факты от прогнозов и мнений.
|
|
46
|
+
|
|
47
|
+
Формат ответа:
|
|
48
|
+
1. Executive Summary (3-5 предложений)
|
|
49
|
+
2. Ключевые находки (с уровнями уверенности)
|
|
50
|
+
3. Детальный анализ (данные, таблицы, сравнения)
|
|
51
|
+
4. Выводы и рекомендации
|
|
52
|
+
5. Пробелы и ограничения
|
|
53
|
+
6. Источники (полный список с URL)
|
|
54
|
+
|
|
55
|
+
Язык: русский. Формат: markdown.`;
|
|
56
|
+
|
|
57
|
+
function parseArgs(argv) {
|
|
58
|
+
const args = argv.slice(2);
|
|
59
|
+
const result = {
|
|
60
|
+
model: DEFAULT_MODEL,
|
|
61
|
+
system: DEFAULT_SYSTEM_PROMPT,
|
|
62
|
+
message: null,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
let i = 0;
|
|
66
|
+
const messageParts = [];
|
|
67
|
+
|
|
68
|
+
while (i < args.length) {
|
|
69
|
+
if (args[i] === '--model' && i + 1 < args.length) {
|
|
70
|
+
result.model = args[++i];
|
|
71
|
+
} else if (args[i] === '--system' && i + 1 < args.length) {
|
|
72
|
+
result.system = args[++i];
|
|
73
|
+
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
74
|
+
console.log(`
|
|
75
|
+
Использование: node perplexity-research.js [опции] "тема исследования"
|
|
76
|
+
|
|
77
|
+
Результат (markdown) выводится в stdout.
|
|
78
|
+
|
|
79
|
+
Опции:
|
|
80
|
+
--model <id> Модель Perplexity (по умолчанию: ${DEFAULT_MODEL})
|
|
81
|
+
--system <text> Системный промпт (по умолчанию: встроенный промпт исследователя)
|
|
82
|
+
-h, --help Показать справку
|
|
83
|
+
`);
|
|
84
|
+
process.exit(0);
|
|
85
|
+
} else {
|
|
86
|
+
messageParts.push(args[i]);
|
|
87
|
+
}
|
|
88
|
+
i++;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
result.message = messageParts.join(' ');
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function loadKiloToken() {
|
|
96
|
+
if (!fs.existsSync(AUTH_FILE)) {
|
|
97
|
+
throw new Error(`Kilo auth file not found: ${AUTH_FILE}\nRun 'kilo auth login' first.`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const auth = JSON.parse(fs.readFileSync(AUTH_FILE, 'utf-8'));
|
|
101
|
+
const kiloAuth = auth.kilo;
|
|
102
|
+
|
|
103
|
+
if (!kiloAuth || !kiloAuth.access) {
|
|
104
|
+
throw new Error('Kilo OAuth token not found in auth.json. Run "kilo auth login" first.');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (kiloAuth.expires && Date.now() > kiloAuth.expires) {
|
|
108
|
+
throw new Error('Kilo OAuth token expired. Run "kilo auth login" to refresh.');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return kiloAuth.access;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function loadEnvFile() {
|
|
115
|
+
const PROJECT_DIR = findProjectRoot();
|
|
116
|
+
const envPath = path.join(PROJECT_DIR, '.workflow', 'config', '.env');
|
|
117
|
+
if (!fs.existsSync(envPath)) return;
|
|
118
|
+
|
|
119
|
+
const content = fs.readFileSync(envPath, 'utf-8');
|
|
120
|
+
for (const line of content.split('\n')) {
|
|
121
|
+
const trimmed = line.trim();
|
|
122
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
123
|
+
const eq = trimmed.indexOf('=');
|
|
124
|
+
if (eq === -1) continue;
|
|
125
|
+
const key = trimmed.slice(0, eq).trim();
|
|
126
|
+
const val = trimmed.slice(eq + 1).trim();
|
|
127
|
+
if (!process.env[key]) {
|
|
128
|
+
process.env[key] = val;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getProxyUrl() {
|
|
134
|
+
return process.env.HTTPS_PROXY || process.env.https_proxy
|
|
135
|
+
|| process.env.HTTP_PROXY || process.env.http_proxy
|
|
136
|
+
|| process.env.ALL_PROXY || process.env.all_proxy
|
|
137
|
+
|| null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function callPerplexityAPI(token, model, systemPrompt, userMessage) {
|
|
141
|
+
return new Promise((resolve, reject) => {
|
|
142
|
+
const payload = JSON.stringify({
|
|
143
|
+
model,
|
|
144
|
+
messages: [
|
|
145
|
+
{ role: 'system', content: systemPrompt },
|
|
146
|
+
{ role: 'user', content: userMessage },
|
|
147
|
+
],
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const targetUrl = new URL(API_URL);
|
|
151
|
+
const proxyUrl = getProxyUrl();
|
|
152
|
+
|
|
153
|
+
const requestHeaders = {
|
|
154
|
+
'Content-Type': 'application/json',
|
|
155
|
+
'Authorization': `Bearer ${token}`,
|
|
156
|
+
'Content-Length': Buffer.byteLength(payload),
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
function handleResponse(res) {
|
|
160
|
+
let data = '';
|
|
161
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
162
|
+
res.on('end', () => {
|
|
163
|
+
if (res.statusCode !== 200) {
|
|
164
|
+
reject(new Error(`API error ${res.statusCode}: ${data}`));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const json = JSON.parse(data);
|
|
169
|
+
resolve(json);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
reject(new Error(`Failed to parse API response: ${e.message}\n${data}`));
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let req;
|
|
177
|
+
|
|
178
|
+
if (proxyUrl) {
|
|
179
|
+
const proxy = new URL(proxyUrl);
|
|
180
|
+
const proxyAuth = proxy.username && proxy.password
|
|
181
|
+
? `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`
|
|
182
|
+
: null;
|
|
183
|
+
|
|
184
|
+
const connectOptions = {
|
|
185
|
+
hostname: proxy.hostname,
|
|
186
|
+
port: parseInt(proxy.port) || 8080,
|
|
187
|
+
method: 'CONNECT',
|
|
188
|
+
path: `${targetUrl.hostname}:443`,
|
|
189
|
+
headers: {
|
|
190
|
+
'Host': `${targetUrl.hostname}:443`,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
if (proxyAuth) {
|
|
195
|
+
connectOptions.headers['Proxy-Authorization'] =
|
|
196
|
+
'Basic ' + Buffer.from(proxyAuth).toString('base64');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
logger.info(`Using proxy: ${proxy.hostname}:${proxy.port}`);
|
|
200
|
+
|
|
201
|
+
const proxyReq = http.request(connectOptions);
|
|
202
|
+
|
|
203
|
+
proxyReq.on('connect', (res, socket) => {
|
|
204
|
+
if (res.statusCode !== 200) {
|
|
205
|
+
reject(new Error(`Proxy CONNECT failed: ${res.statusCode}`));
|
|
206
|
+
socket.destroy();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const tlsOptions = {
|
|
211
|
+
hostname: targetUrl.hostname,
|
|
212
|
+
path: targetUrl.pathname,
|
|
213
|
+
method: 'POST',
|
|
214
|
+
headers: requestHeaders,
|
|
215
|
+
socket,
|
|
216
|
+
agent: false,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
req = https.request(tlsOptions, handleResponse);
|
|
220
|
+
req.on('error', (e) => reject(new Error(`Request failed: ${e.message}`)));
|
|
221
|
+
req.setTimeout(600000, () => {
|
|
222
|
+
req.destroy();
|
|
223
|
+
reject(new Error('Request timeout (10 minutes)'));
|
|
224
|
+
});
|
|
225
|
+
req.write(payload);
|
|
226
|
+
req.end();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
proxyReq.on('error', (e) => reject(new Error(`Proxy connection failed: ${e.message}`)));
|
|
230
|
+
proxyReq.setTimeout(30000, () => {
|
|
231
|
+
proxyReq.destroy();
|
|
232
|
+
reject(new Error('Proxy connection timeout'));
|
|
233
|
+
});
|
|
234
|
+
proxyReq.end();
|
|
235
|
+
|
|
236
|
+
} else {
|
|
237
|
+
const options = {
|
|
238
|
+
hostname: targetUrl.hostname,
|
|
239
|
+
port: 443,
|
|
240
|
+
path: targetUrl.pathname,
|
|
241
|
+
method: 'POST',
|
|
242
|
+
headers: requestHeaders,
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
req = https.request(options, handleResponse);
|
|
246
|
+
req.on('error', (e) => reject(new Error(`Request failed: ${e.message}`)));
|
|
247
|
+
req.setTimeout(600000, () => {
|
|
248
|
+
req.destroy();
|
|
249
|
+
reject(new Error('Request timeout (10 minutes)'));
|
|
250
|
+
});
|
|
251
|
+
req.write(payload);
|
|
252
|
+
req.end();
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function formatOutput(apiResponse, model, userMessage) {
|
|
258
|
+
const choice = apiResponse.choices?.[0];
|
|
259
|
+
if (!choice) throw new Error('No response from API');
|
|
260
|
+
|
|
261
|
+
const content = choice.message?.content || '';
|
|
262
|
+
const annotations = choice.message?.annotations || [];
|
|
263
|
+
|
|
264
|
+
let output = content;
|
|
265
|
+
|
|
266
|
+
if (annotations.length > 0) {
|
|
267
|
+
const urlCitations = annotations.filter(a => a.type === 'url_citation' && a.url_citation?.url);
|
|
268
|
+
const uniqueUrls = [...new Set(urlCitations.map(a => a.url_citation.url))];
|
|
269
|
+
|
|
270
|
+
if (uniqueUrls.length > 0) {
|
|
271
|
+
output += '\n\n---\n\n## Источники (автоматические цитаты)\n\n';
|
|
272
|
+
uniqueUrls.forEach((url, i) => {
|
|
273
|
+
const citation = urlCitations.find(a => a.url_citation.url === url);
|
|
274
|
+
const title = citation.url_citation.title || url;
|
|
275
|
+
output += `${i + 1}. [${title}](${url})\n`;
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return output;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function main() {
|
|
284
|
+
loadEnvFile();
|
|
285
|
+
const args = parseArgs(process.argv);
|
|
286
|
+
|
|
287
|
+
if (!args.message) {
|
|
288
|
+
console.error('Ошибка: не указана тема исследования');
|
|
289
|
+
console.error('Использование: node perplexity-research.js "тема исследования"');
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
logger.info(`Research query: ${args.message}`);
|
|
294
|
+
logger.info(`Model: ${args.model}`);
|
|
295
|
+
|
|
296
|
+
const token = loadKiloToken();
|
|
297
|
+
|
|
298
|
+
console.error(`Запуск исследования через ${args.model}...`);
|
|
299
|
+
console.error(`Ожидание ответа (deep research может занять до 5-10 минут)...`);
|
|
300
|
+
|
|
301
|
+
const response = await callPerplexityAPI(token, args.model, args.system, args.message);
|
|
302
|
+
const output = formatOutput(response, args.model, args.message);
|
|
303
|
+
const usage = response.usage || {};
|
|
304
|
+
|
|
305
|
+
// Результат — в stdout
|
|
306
|
+
console.log(output);
|
|
307
|
+
|
|
308
|
+
// Метаданные — в stderr
|
|
309
|
+
console.error(`Готово. Токены: ${usage.total_tokens || 'N/A'}, стоимость: $${usage.cost || 'N/A'}`);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
main().catch((err) => {
|
|
313
|
+
console.error(`Ошибка: ${err.message}`);
|
|
314
|
+
process.exit(1);
|
|
315
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Шаблон: Краткая справка
|
|
2
|
+
|
|
3
|
+
Используется для быстрых исследовательских ответов, когда полный отчёт избыточен.
|
|
4
|
+
|
|
5
|
+
## Структура
|
|
6
|
+
|
|
7
|
+
```markdown
|
|
8
|
+
# Справка: {Тема}
|
|
9
|
+
|
|
10
|
+
**Дата:** {YYYY-MM-DD} | **Заказчик:** {тикет-ID}
|
|
11
|
+
|
|
12
|
+
## Ответ
|
|
13
|
+
|
|
14
|
+
{2-3 абзаца с ключевыми данными и выводами}
|
|
15
|
+
|
|
16
|
+
## Ключевые данные
|
|
17
|
+
|
|
18
|
+
| Метрика | Значение | Источник | Уверенность |
|
|
19
|
+
|---------|----------|----------|-------------|
|
|
20
|
+
| {метрика} | {значение} | {источник} | [HIGH/MEDIUM/LOW] |
|
|
21
|
+
|
|
22
|
+
## Источники
|
|
23
|
+
|
|
24
|
+
1. {Название} — {URL} ({дата})
|
|
25
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Шаблон: Исследовательский отчёт
|
|
2
|
+
|
|
3
|
+
## Структура отчёта
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
# {Тема исследования}
|
|
7
|
+
|
|
8
|
+
**Дата исследования:** {YYYY-MM-DD}
|
|
9
|
+
**Заказчик:** {тикет-ID, скил}
|
|
10
|
+
**Исследовательский вопрос:** {формулировка}
|
|
11
|
+
**Скоуп:** {что входит и не входит}
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Executive Summary
|
|
16
|
+
|
|
17
|
+
{3-5 предложений: главные находки, ключевой вывод, уровень уверенности}
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Ключевые находки
|
|
22
|
+
|
|
23
|
+
### 1. {Находка}
|
|
24
|
+
**Уверенность:** [HIGH/MEDIUM/LOW]
|
|
25
|
+
|
|
26
|
+
{Описание находки}
|
|
27
|
+
|
|
28
|
+
| Источник | Данные | Дата |
|
|
29
|
+
|----------|--------|------|
|
|
30
|
+
| {название} | {факт/число} | {дата} |
|
|
31
|
+
|
|
32
|
+
### 2. {Находка}
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Детальный анализ
|
|
38
|
+
|
|
39
|
+
### {Подтема 1}
|
|
40
|
+
|
|
41
|
+
{Развёрнутый анализ с данными, таблицами, сравнениями}
|
|
42
|
+
|
|
43
|
+
### {Подтема 2}
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Выводы и рекомендации
|
|
49
|
+
|
|
50
|
+
| # | Вывод | Уверенность | Рекомендация |
|
|
51
|
+
|---|-------|-------------|--------------|
|
|
52
|
+
| 1 | {тезис} | [HIGH] | {что делать} |
|
|
53
|
+
| 2 | {тезис} | [MEDIUM] | {что делать} |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Пробелы и ограничения
|
|
58
|
+
|
|
59
|
+
- {Что не удалось найти и почему}
|
|
60
|
+
- {Какие данные требуют дополнительной верификации}
|
|
61
|
+
- {Известные ограничения методологии}
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## За пределами скоупа
|
|
66
|
+
|
|
67
|
+
{Интересные находки, не входящие в скоуп, но потенциально полезные}
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Источники
|
|
72
|
+
|
|
73
|
+
| # | Название | URL | Тип | Дата | Оценка |
|
|
74
|
+
|---|----------|-----|-----|------|--------|
|
|
75
|
+
| 1 | {название} | {url} | {тип} | {дата} | {A/B/C} |
|
|
76
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Воркфлоу: BENCHMARK — Сбор бенчмарков
|
|
2
|
+
|
|
3
|
+
Сбор отраслевых бенчмарков и лучших практик для сравнения с текущими показателями.
|
|
4
|
+
|
|
5
|
+
## Алгоритм выполнения
|
|
6
|
+
|
|
7
|
+
### 1. Определи что бенчмаркить
|
|
8
|
+
|
|
9
|
+
- Какие метрики нужны (retention, conversion, ARPU, etc.)
|
|
10
|
+
- В какой нише/сегменте
|
|
11
|
+
- Какой масштаб продукта (стартап vs enterprise)
|
|
12
|
+
|
|
13
|
+
### 2. Собери бенчмарки
|
|
14
|
+
|
|
15
|
+
Приоритет источников:
|
|
16
|
+
1. Отраслевые отчёты с методологией (Mixpanel, Amplitude, Lenny's Newsletter)
|
|
17
|
+
2. Публичные данные компаний (S-1 filings, earnings reports)
|
|
18
|
+
3. Агрегаторы бенчмарков (ChartMogul, ProfitWell)
|
|
19
|
+
4. Экспертные статьи с данными
|
|
20
|
+
5. Кейс-стади
|
|
21
|
+
|
|
22
|
+
### 3. Нормализуй данные
|
|
23
|
+
|
|
24
|
+
- Привести к единой методологии (DAU vs WAU vs MAU)
|
|
25
|
+
- Учесть разницу в определениях (что считается active user?)
|
|
26
|
+
- Учесть сегмент (mobile vs web vs extension)
|
|
27
|
+
- Учесть stage (pre-PMF vs growth vs mature)
|
|
28
|
+
|
|
29
|
+
### 4. Сформируй таблицу бенчмарков
|
|
30
|
+
|
|
31
|
+
| Метрика | Bottom 25% | Median | Top 25% | Best-in-class | Наш | Источник |
|
|
32
|
+
|---------|-----------|--------|---------|--------------|-----|----------|
|
|
33
|
+
| ... | ... | ... | ... | ... | ... | ... |
|
|
34
|
+
|
|
35
|
+
### 5. Проанализируй gaps
|
|
36
|
+
|
|
37
|
+
Для каждой метрики где наш показатель ниже медианы:
|
|
38
|
+
- Насколько критичен gap
|
|
39
|
+
- Что делают top-performers иначе
|
|
40
|
+
- Реалистично ли достичь медианы и за какой срок
|
|
41
|
+
|
|
42
|
+
### 6. Синтезируй выводы
|
|
43
|
+
|
|
44
|
+
→ Загрузи `algorithms/synthesis.md`
|
|
45
|
+
|
|
46
|
+
### 7. Сформируй отчёт
|
|
47
|
+
|
|
48
|
+
→ Используй `templates/research-report.md`
|
|
49
|
+
|
|
50
|
+
### 8. Валидация
|
|
51
|
+
|
|
52
|
+
- [ ] Бенчмарки из 2+ источников для ключевых метрик
|
|
53
|
+
- [ ] Данные нормализованы (единая методология)
|
|
54
|
+
- [ ] Указаны сегмент и stage для каждого бенчмарка
|
|
55
|
+
- [ ] Gap-анализ с приоритизацией
|
|
56
|
+
- [ ] Источники с датами
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Воркфлоу: COMPETITOR — Анализ конкурентов
|
|
2
|
+
|
|
3
|
+
Глубокий анализ конкурентов: продукты, позиционирование, метрики, сильные/слабые стороны.
|
|
4
|
+
|
|
5
|
+
## Алгоритм выполнения
|
|
6
|
+
|
|
7
|
+
### 1. Определи скоуп
|
|
8
|
+
|
|
9
|
+
- Каких конкурентов анализировать (или найти самостоятельно)
|
|
10
|
+
- По каким параметрам сравнивать
|
|
11
|
+
- Прямые vs косвенные конкуренты
|
|
12
|
+
|
|
13
|
+
### 2. Составь список конкурентов
|
|
14
|
+
|
|
15
|
+
Если не задан:
|
|
16
|
+
1. Поиск по ключевым запросам в нише
|
|
17
|
+
2. Маркетплейсы/сторы (Chrome Web Store, App Store, etc.)
|
|
18
|
+
3. Обзорные статьи "Top N {category}"
|
|
19
|
+
4. Альтернативы (AlternativeTo, G2, Capterra)
|
|
20
|
+
|
|
21
|
+
### 3. Собери данные по каждому конкуренту
|
|
22
|
+
|
|
23
|
+
| Параметр | Что искать |
|
|
24
|
+
|----------|-----------|
|
|
25
|
+
| Продукт | Функции, цены, модель монетизации |
|
|
26
|
+
| Масштаб | Пользователи, загрузки, revenue (если публично) |
|
|
27
|
+
| Позиционирование | Messaging, целевая аудитория, USP |
|
|
28
|
+
| Каналы | Как привлекают пользователей |
|
|
29
|
+
| Отзывы | Рейтинги, частые жалобы, что хвалят |
|
|
30
|
+
| Технологии | Стек, интеграции, открытый код |
|
|
31
|
+
|
|
32
|
+
→ Загрузи `algorithms/source-scoring.md` для оценки данных
|
|
33
|
+
|
|
34
|
+
### 4. Проведи сравнительный анализ
|
|
35
|
+
|
|
36
|
+
Создай comparison matrix:
|
|
37
|
+
|
|
38
|
+
| Параметр | Конкурент A | Конкурент B | Наш продукт |
|
|
39
|
+
|----------|------------|------------|-------------|
|
|
40
|
+
| ... | ... | ... | ... |
|
|
41
|
+
|
|
42
|
+
### 5. Определи паттерны
|
|
43
|
+
|
|
44
|
+
- Общие стратегии успешных конкурентов
|
|
45
|
+
- Незанятые ниши
|
|
46
|
+
- Типичные ошибки
|
|
47
|
+
- Тренды в продуктах
|
|
48
|
+
|
|
49
|
+
### 6. Синтезируй выводы
|
|
50
|
+
|
|
51
|
+
→ Загрузи `algorithms/synthesis.md`
|
|
52
|
+
|
|
53
|
+
### 7. Сформируй отчёт
|
|
54
|
+
|
|
55
|
+
→ Используй `templates/research-report.md`
|
|
56
|
+
|
|
57
|
+
### 8. Валидация
|
|
58
|
+
|
|
59
|
+
- [ ] Минимум 5 конкурентов проанализировано (или все если < 5)
|
|
60
|
+
- [ ] Данные по каждому из одного периода
|
|
61
|
+
- [ ] Comparison matrix заполнена
|
|
62
|
+
- [ ] Выводы actionable для заказчика
|
|
63
|
+
- [ ] Источники указаны для каждого факта
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Воркфлоу: CUSTOM — Кастомное исследование
|
|
2
|
+
|
|
3
|
+
Исследование по произвольному ТЗ, не попадающее в стандартные типы.
|
|
4
|
+
|
|
5
|
+
## Алгоритм выполнения
|
|
6
|
+
|
|
7
|
+
### 1. Определи исследовательский вопрос
|
|
8
|
+
|
|
9
|
+
Из тикета извлеки:
|
|
10
|
+
- Что именно нужно узнать (конкретный вопрос)
|
|
11
|
+
- Для чего (контекст решения)
|
|
12
|
+
- Глубина: справка (brief) vs полное исследование (report)
|
|
13
|
+
- Ограничения по скоупу
|
|
14
|
+
|
|
15
|
+
### 2. Выбери стратегию поиска
|
|
16
|
+
|
|
17
|
+
→ Загрузи `knowledge/research-methodology.md`
|
|
18
|
+
|
|
19
|
+
- Обзорный вопрос → Breadth-First
|
|
20
|
+
- Конкретный вопрос → Depth-First
|
|
21
|
+
- Проверка гипотезы → Adversarial
|
|
22
|
+
|
|
23
|
+
### 3. Проведи исследование
|
|
24
|
+
|
|
25
|
+
1. Сформулируй 3-5 поисковых запросов
|
|
26
|
+
2. Для каждого запроса собери топ-5 релевантных результатов
|
|
27
|
+
3. Оцени источники → `algorithms/source-scoring.md`
|
|
28
|
+
4. Валидируй данные → `knowledge/data-validation.md`
|
|
29
|
+
|
|
30
|
+
### 4. Синтезируй
|
|
31
|
+
|
|
32
|
+
→ Загрузи `algorithms/synthesis.md`
|
|
33
|
+
|
|
34
|
+
### 5. Сформируй результат
|
|
35
|
+
|
|
36
|
+
- Справка → `templates/brief-summary.md`
|
|
37
|
+
- Полное исследование → `templates/research-report.md`
|
|
38
|
+
|
|
39
|
+
### 6. Валидация
|
|
40
|
+
|
|
41
|
+
- [ ] Исследовательский вопрос отвечен
|
|
42
|
+
- [ ] Ключевые данные подкреплены источниками
|
|
43
|
+
- [ ] Уровни уверенности указаны
|
|
44
|
+
- [ ] Пробелы в данных явно отмечены
|
|
45
|
+
- [ ] Формат соответствует глубине запроса
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Воркфлоу: MARKET — Исследование рынка
|
|
2
|
+
|
|
3
|
+
Проведение глубокого исследования рынка: размер, сегменты, динамика, ключевые игроки.
|
|
4
|
+
|
|
5
|
+
## Алгоритм выполнения
|
|
6
|
+
|
|
7
|
+
### 1. Определи скоуп исследования
|
|
8
|
+
|
|
9
|
+
Из тикета извлеки:
|
|
10
|
+
- Какой рынок/сегмент исследовать
|
|
11
|
+
- Географию (глобально, регион, страна)
|
|
12
|
+
- Временной горизонт (текущий, прогноз на N лет)
|
|
13
|
+
- Для чего нужны данные (контекст заказчика)
|
|
14
|
+
|
|
15
|
+
### 2. Собери данные о размере рынка
|
|
16
|
+
|
|
17
|
+
Ищи в следующем порядке:
|
|
18
|
+
1. Отраслевые отчёты (Statista, Grand View Research, Mordor Intelligence)
|
|
19
|
+
2. Аналитические платформы (SimilarWeb, Sensor Tower)
|
|
20
|
+
3. Пресс-релизы и финотчёты ключевых игроков
|
|
21
|
+
4. Экспертные оценки
|
|
22
|
+
|
|
23
|
+
Собери: TAM, SAM, SOM (если применимо), CAGR, revenue, users.
|
|
24
|
+
|
|
25
|
+
→ Загрузи `knowledge/source-evaluation.md` для оценки источников
|
|
26
|
+
→ Загрузи `algorithms/source-scoring.md` для скоринга
|
|
27
|
+
|
|
28
|
+
### 3. Проанализируй сегменты
|
|
29
|
+
|
|
30
|
+
- Определи основные сегменты рынка
|
|
31
|
+
- Размер каждого сегмента
|
|
32
|
+
- Темпы роста по сегментам
|
|
33
|
+
- Какой сегмент релевантен для заказчика
|
|
34
|
+
|
|
35
|
+
### 4. Определи ключевых игроков
|
|
36
|
+
|
|
37
|
+
| Игрок | Доля рынка | Продукт | Позиционирование |
|
|
38
|
+
|-------|-----------|---------|-----------------|
|
|
39
|
+
| ... | ... | ... | ... |
|
|
40
|
+
|
|
41
|
+
### 5. Выяви тренды и драйверы
|
|
42
|
+
|
|
43
|
+
- Что двигает рынок вверх
|
|
44
|
+
- Что тормозит
|
|
45
|
+
- Регуляторные факторы
|
|
46
|
+
- Технологические сдвиги
|
|
47
|
+
|
|
48
|
+
### 6. Синтезируй выводы
|
|
49
|
+
|
|
50
|
+
→ Загрузи `algorithms/synthesis.md`
|
|
51
|
+
→ Загрузи `knowledge/data-validation.md` для проверки данных
|
|
52
|
+
|
|
53
|
+
### 7. Сформируй отчёт
|
|
54
|
+
|
|
55
|
+
→ Используй `templates/research-report.md`
|
|
56
|
+
|
|
57
|
+
### 8. Валидация
|
|
58
|
+
|
|
59
|
+
- [ ] Все ключевые числа имеют источники
|
|
60
|
+
- [ ] TAM/SAM/SOM рассчитаны корректно (сумма долей ≈ 100%)
|
|
61
|
+
- [ ] Данные актуальны (не старше 2 лет для размера рынка)
|
|
62
|
+
- [ ] Указаны уровни уверенности
|
|
63
|
+
- [ ] Есть executive summary
|
|
64
|
+
- [ ] Пробелы в данных явно указаны
|