feat(parse-prd): Add research flag to parse-prd command for enhanced PRD analysis. Significantly improves parse PRD system prompt when used with research.

This commit is contained in:
Eyal Toledano
2025-05-22 02:57:51 -04:00
parent 34c769bcd0
commit 70f4054f26
5 changed files with 72 additions and 19 deletions

View File

@@ -0,0 +1,13 @@
---
'task-master-ai': patch
---
Add `--research` flag to parse-prd command, enabling enhanced task generation from PRD files. When used, Taskmaster leverages the Perplexity AI research model to:
- Research current technologies and best practices relevant to the project
- Identify technical challenges and security concerns not explicitly mentioned in the PRD
- Include specific library recommendations with version numbers
- Provide more detailed implementation guidance based on industry standards
- Create more accurate dependency relationships between tasks
This results in higher quality, more actionable tasks with minimal additional effort.

View File

@@ -31,6 +31,7 @@ export async function parsePRDDirect(args, log, context = {}) {
numTasks: numTasksArg, numTasks: numTasksArg,
force, force,
append, append,
research,
projectRoot projectRoot
} = args; } = args;
@@ -114,8 +115,12 @@ export async function parsePRDDirect(args, log, context = {}) {
} }
} }
if (research) {
logWrapper.info('Research mode enabled. Using Perplexity AI for enhanced PRD analysis.');
}
logWrapper.info( logWrapper.info(
`Parsing PRD via direct function. Input: ${inputPath}, Output: ${outputPath}, NumTasks: ${numTasks}, Force: ${force}, Append: ${append}, ProjectRoot: ${projectRoot}` `Parsing PRD via direct function. Input: ${inputPath}, Output: ${outputPath}, NumTasks: ${numTasks}, Force: ${force}, Append: ${append}, Research: ${research}, ProjectRoot: ${projectRoot}`
); );
const wasSilent = isSilentMode(); const wasSilent = isSilentMode();
@@ -135,6 +140,7 @@ export async function parsePRDDirect(args, log, context = {}) {
projectRoot, projectRoot,
force, force,
append, append,
research,
commandName: 'parse-prd', commandName: 'parse-prd',
outputType: 'mcp' outputType: 'mcp'
}, },

View File

@@ -49,6 +49,11 @@ export function registerParsePRDTool(server) {
.optional() .optional()
.default(false) .default(false)
.describe('Append generated tasks to existing file.'), .describe('Append generated tasks to existing file.'),
research: z
.boolean()
.optional()
.default(false)
.describe('Use the research model for research-backed task generation, providing more comprehensive, accurate and up-to-date task details.'),
projectRoot: z projectRoot: z
.string() .string()
.describe('The directory of the project. Must be an absolute path.') .describe('The directory of the project. Must be an absolute path.')
@@ -68,6 +73,7 @@ export function registerParsePRDTool(server) {
numTasks: args.numTasks, numTasks: args.numTasks,
force: args.force, force: args.force,
append: args.append, append: args.append,
research: args.research,
projectRoot: args.projectRoot projectRoot: args.projectRoot
}, },
log, log,

View File

@@ -507,6 +507,10 @@ function registerCommands(programInstance) {
'--append', '--append',
'Append new tasks to existing tasks.json instead of overwriting' 'Append new tasks to existing tasks.json instead of overwriting'
) )
.option(
'-r, --research',
'Use Perplexity AI for research-backed task generation, providing more comprehensive and accurate task breakdown'
)
.action(async (file, options) => { .action(async (file, options) => {
// Use input option if file argument not provided // Use input option if file argument not provided
const inputFile = file || options.input; const inputFile = file || options.input;
@@ -515,6 +519,7 @@ function registerCommands(programInstance) {
const outputPath = options.output; const outputPath = options.output;
const force = options.force || false; const force = options.force || false;
const append = options.append || false; const append = options.append || false;
const research = options.research || false;
let useForce = force; let useForce = force;
let useAppend = append; let useAppend = append;
@@ -547,7 +552,8 @@ function registerCommands(programInstance) {
spinner = ora('Parsing PRD and generating tasks...\n').start(); spinner = ora('Parsing PRD and generating tasks...\n').start();
await parsePRD(defaultPrdPath, outputPath, numTasks, { await parsePRD(defaultPrdPath, outputPath, numTasks, {
append: useAppend, // Changed key from useAppend to append append: useAppend, // Changed key from useAppend to append
force: useForce // Changed key from useForce to force force: useForce, // Changed key from useForce to force
research: research
}); });
spinner.succeed('Tasks generated successfully!'); spinner.succeed('Tasks generated successfully!');
return; return;
@@ -571,13 +577,15 @@ function registerCommands(programInstance) {
' -o, --output <file> Output file path (default: "tasks/tasks.json")\n' + ' -o, --output <file> Output file path (default: "tasks/tasks.json")\n' +
' -n, --num-tasks <number> Number of tasks to generate (default: 10)\n' + ' -n, --num-tasks <number> Number of tasks to generate (default: 10)\n' +
' -f, --force Skip confirmation when overwriting existing tasks\n' + ' -f, --force Skip confirmation when overwriting existing tasks\n' +
' --append Append new tasks to existing tasks.json instead of overwriting\n\n' + ' --append Append new tasks to existing tasks.json instead of overwriting\n' +
' -r, --research Use Perplexity AI for research-backed task generation\n\n' +
chalk.cyan('Example:') + chalk.cyan('Example:') +
'\n' + '\n' +
' task-master parse-prd requirements.txt --num-tasks 15\n' + ' task-master parse-prd requirements.txt --num-tasks 15\n' +
' task-master parse-prd --input=requirements.txt\n' + ' task-master parse-prd --input=requirements.txt\n' +
' task-master parse-prd --force\n' + ' task-master parse-prd --force\n' +
' task-master parse-prd requirements_v2.txt --append\n\n' + ' task-master parse-prd requirements_v2.txt --append\n' +
' task-master parse-prd requirements.txt --research\n\n' +
chalk.yellow('Note: This command will:') + chalk.yellow('Note: This command will:') +
'\n' + '\n' +
' 1. Look for a PRD file at scripts/prd.txt by default\n' + ' 1. Look for a PRD file at scripts/prd.txt by default\n' +
@@ -605,12 +613,16 @@ function registerCommands(programInstance) {
if (append) { if (append) {
console.log(chalk.blue('Appending to existing tasks...')); console.log(chalk.blue('Appending to existing tasks...'));
} }
if (research) {
console.log(chalk.blue('Using Perplexity AI for research-backed task generation'));
}
spinner = ora('Parsing PRD and generating tasks...\n').start(); spinner = ora('Parsing PRD and generating tasks...\n').start();
await parsePRD(inputFile, outputPath, numTasks, { await parsePRD(inputFile, outputPath, numTasks, {
useAppend: useAppend, useAppend: useAppend,
useForce: useForce useForce: useForce,
}); research: research
});
spinner.succeed('Tasks generated successfully!'); spinner.succeed('Tasks generated successfully!');
} catch (error) { } catch (error) {
if (spinner) { if (spinner) {

View File

@@ -50,6 +50,7 @@ const prdResponseSchema = z.object({
* @param {Object} options - Additional options * @param {Object} options - Additional options
* @param {boolean} [options.force=false] - Whether to overwrite existing tasks.json. * @param {boolean} [options.force=false] - Whether to overwrite existing tasks.json.
* @param {boolean} [options.append=false] - Append to existing tasks file. * @param {boolean} [options.append=false] - Append to existing tasks file.
* @param {boolean} [options.research=false] - Use research model for enhanced PRD analysis.
* @param {Object} [options.reportProgress] - Function to report progress (optional, likely unused). * @param {Object} [options.reportProgress] - Function to report progress (optional, likely unused).
* @param {Object} [options.mcpLog] - MCP logger object (optional). * @param {Object} [options.mcpLog] - MCP logger object (optional).
* @param {Object} [options.session] - Session object from MCP server (optional). * @param {Object} [options.session] - Session object from MCP server (optional).
@@ -63,7 +64,8 @@ async function parsePRD(prdPath, tasksPath, numTasks, options = {}) {
session, session,
projectRoot, projectRoot,
force = false, force = false,
append = false append = false,
research = false
} = options; } = options;
const isMCP = !!mcpLog; const isMCP = !!mcpLog;
const outputFormat = isMCP ? 'json' : 'text'; const outputFormat = isMCP ? 'json' : 'text';
@@ -90,7 +92,7 @@ async function parsePRD(prdPath, tasksPath, numTasks, options = {}) {
} }
}; };
report(`Parsing PRD file: ${prdPath}, Force: ${force}, Append: ${append}`); report(`Parsing PRD file: ${prdPath}, Force: ${force}, Append: ${append}, Research: ${research}`);
let existingTasks = []; let existingTasks = [];
let nextId = 1; let nextId = 1;
@@ -148,8 +150,22 @@ async function parsePRD(prdPath, tasksPath, numTasks, options = {}) {
throw new Error(`Input file ${prdPath} is empty or could not be read.`); throw new Error(`Input file ${prdPath} is empty or could not be read.`);
} }
// Build system prompt for PRD parsing // Research-specific enhancements to the system prompt
const systemPrompt = `You are an AI assistant specialized in analyzing Product Requirements Documents (PRDs) and generating a structured, logically ordered, dependency-aware and sequenced list of development tasks in JSON format. const researchPromptAddition = research
? `\nBefore breaking down the PRD into tasks, you will:
1. Research and analyze the latest technologies, libraries, frameworks, and best practices that would be appropriate for this project
2. Identify any potential technical challenges, security concerns, or scalability issues not explicitly mentioned in the PRD without discarding any explicit requirements or going overboard with complexity -- always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches
3. Consider current industry standards and evolving trends relevant to this project (this step aims to solve LLM hallucinations and out of date information due to training data cutoff dates)
4. Evaluate alternative implementation approaches and recommend the most efficient path
5. Include specific library versions, helpful APIs, and concrete implementation guidance based on your research
6. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches
Your task breakdown should incorporate this research, resulting in more detailed implementation guidance, more accurate dependency mapping, and more precise technology recommendations than would be possible from the PRD text alone, while maintaining all explicit requirements and best practices and all details and nuances of the PRD.`
: '';
// Base system prompt for PRD parsing
const systemPrompt = `You are an AI assistant specialized in analyzing Product Requirements Documents (PRDs) and generating a structured, logically ordered, dependency-aware and sequenced list of development tasks in JSON format.${researchPromptAddition}
Analyze the provided PRD content and generate approximately ${numTasks} top-level development tasks. If the complexity or the level of detail of the PRD is high, generate more tasks relative to the complexity of the PRD Analyze the provided PRD content and generate approximately ${numTasks} top-level development tasks. If the complexity or the level of detail of the PRD is high, generate more tasks relative to the complexity of the PRD
Each task should represent a logical unit of work needed to implement the requirements and focus on the most direct and effective way to implement the requirements without unnecessary complexity or overengineering. Include pseudo-code, implementation details, and test strategy for each task. Find the most up to date information to implement each task. Each task should represent a logical unit of work needed to implement the requirements and focus on the most direct and effective way to implement the requirements without unnecessary complexity or overengineering. Include pseudo-code, implementation details, and test strategy for each task. Find the most up to date information to implement each task.
Assign sequential IDs starting from ${nextId}. Infer title, description, details, and test strategy for each task based *only* on the PRD content. Assign sequential IDs starting from ${nextId}. Infer title, description, details, and test strategy for each task based *only* on the PRD content.
@@ -176,13 +192,13 @@ Guidelines:
5. Include clear validation/testing approach for each task 5. Include clear validation/testing approach for each task
6. Set appropriate dependency IDs (a task can only depend on tasks with lower IDs, potentially including existing tasks with IDs less than ${nextId} if applicable) 6. Set appropriate dependency IDs (a task can only depend on tasks with lower IDs, potentially including existing tasks with IDs less than ${nextId} if applicable)
7. Assign priority (high/medium/low) based on criticality and dependency order 7. Assign priority (high/medium/low) based on criticality and dependency order
8. Include detailed implementation guidance in the "details" field 8. Include detailed implementation guidance in the "details" field${research ? ', with specific libraries and version recommendations based on your research' : ''}
9. If the PRD contains specific requirements for libraries, database schemas, frameworks, tech stacks, or any other implementation details, STRICTLY ADHERE to these requirements in your task breakdown and do not discard them under any circumstance 9. If the PRD contains specific requirements for libraries, database schemas, frameworks, tech stacks, or any other implementation details, STRICTLY ADHERE to these requirements in your task breakdown and do not discard them under any circumstance
10. Focus on filling in any gaps left by the PRD or areas that aren't fully specified, while preserving all explicit requirements 10. Focus on filling in any gaps left by the PRD or areas that aren't fully specified, while preserving all explicit requirements
11. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches`; 11. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches${research ? '\n12. For each task, include specific, actionable guidance based on current industry standards and best practices discovered through research' : ''}`;
// Build user prompt with PRD content // Build user prompt with PRD content
const userPrompt = `Here's the Product Requirements Document (PRD) to break down into approximately ${numTasks} tasks, starting IDs from ${nextId}:\n\n${prdContent}\n\n const userPrompt = `Here's the Product Requirements Document (PRD) to break down into approximately ${numTasks} tasks, starting IDs from ${nextId}:${research ? '\n\nRemember to thoroughly research current best practices and technologies before task breakdown to provide specific, actionable implementation details.' : ''}\n\n${prdContent}\n\n
Return your response in this format: Return your response in this format:
{ {
@@ -204,11 +220,11 @@ Guidelines:
}`; }`;
// Call the unified AI service // Call the unified AI service
report('Calling AI service to generate tasks from PRD...', 'info'); report(`Calling AI service to generate tasks from PRD${research ? ' with research-backed analysis' : ''}...`, 'info');
// Call generateObjectService with the CORRECT schema and additional telemetry params // Call generateObjectService with the CORRECT schema and additional telemetry params
aiServiceResponse = await generateObjectService({ aiServiceResponse = await generateObjectService({
role: 'main', role: research ? 'research' : 'main', // Use research role if flag is set
session: session, session: session,
projectRoot: projectRoot, projectRoot: projectRoot,
schema: prdResponseSchema, schema: prdResponseSchema,
@@ -224,7 +240,7 @@ Guidelines:
if (!fs.existsSync(tasksDir)) { if (!fs.existsSync(tasksDir)) {
fs.mkdirSync(tasksDir, { recursive: true }); fs.mkdirSync(tasksDir, { recursive: true });
} }
logFn.success('Successfully parsed PRD via AI service.\n'); logFn.success(`Successfully parsed PRD via AI service${research ? ' with research-backed analysis' : ''}.`);
// Validate and Process Tasks // Validate and Process Tasks
// const generatedData = aiServiceResponse?.mainResult?.object; // const generatedData = aiServiceResponse?.mainResult?.object;
@@ -294,7 +310,7 @@ Guidelines:
// Write the final tasks to the file // Write the final tasks to the file
writeJSON(tasksPath, outputData); writeJSON(tasksPath, outputData);
report( report(
`Successfully ${append ? 'appended' : 'generated'} ${processedNewTasks.length} tasks in ${tasksPath}`, `Successfully ${append ? 'appended' : 'generated'} ${processedNewTasks.length} tasks in ${tasksPath}${research ? ' with research-backed analysis' : ''}`,
'success' 'success'
); );
@@ -306,7 +322,7 @@ Guidelines:
console.log( console.log(
boxen( boxen(
chalk.green( chalk.green(
`Successfully generated ${processedNewTasks.length} new tasks. Total tasks in ${tasksPath}: ${finalTasks.length}` `Successfully generated ${processedNewTasks.length} new tasks${research ? ' with research-backed analysis' : ''}. Total tasks in ${tasksPath}: ${finalTasks.length}`
), ),
{ padding: 1, borderColor: 'green', borderStyle: 'round' } { padding: 1, borderColor: 'green', borderStyle: 'round' }
) )