#
tokens: 48283/50000 7/975 files (page 38/69)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 38 of 69. Use http://codebase.md/eyaltoledano/claude-task-master?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .changeset
│   ├── config.json
│   └── README.md
├── .claude
│   ├── commands
│   │   └── dedupe.md
│   └── TM_COMMANDS_GUIDE.md
├── .claude-plugin
│   └── marketplace.json
├── .coderabbit.yaml
├── .cursor
│   ├── mcp.json
│   └── rules
│       ├── ai_providers.mdc
│       ├── ai_services.mdc
│       ├── architecture.mdc
│       ├── changeset.mdc
│       ├── commands.mdc
│       ├── context_gathering.mdc
│       ├── cursor_rules.mdc
│       ├── dependencies.mdc
│       ├── dev_workflow.mdc
│       ├── git_workflow.mdc
│       ├── glossary.mdc
│       ├── mcp.mdc
│       ├── new_features.mdc
│       ├── self_improve.mdc
│       ├── tags.mdc
│       ├── taskmaster.mdc
│       ├── tasks.mdc
│       ├── telemetry.mdc
│       ├── test_workflow.mdc
│       ├── tests.mdc
│       ├── ui.mdc
│       └── utilities.mdc
├── .cursorignore
├── .env.example
├── .github
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.md
│   │   ├── enhancements---feature-requests.md
│   │   └── feedback.md
│   ├── PULL_REQUEST_TEMPLATE
│   │   ├── bugfix.md
│   │   ├── config.yml
│   │   ├── feature.md
│   │   └── integration.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── scripts
│   │   ├── auto-close-duplicates.mjs
│   │   ├── backfill-duplicate-comments.mjs
│   │   ├── check-pre-release-mode.mjs
│   │   ├── parse-metrics.mjs
│   │   ├── release.mjs
│   │   ├── tag-extension.mjs
│   │   ├── utils.mjs
│   │   └── validate-changesets.mjs
│   └── workflows
│       ├── auto-close-duplicates.yml
│       ├── backfill-duplicate-comments.yml
│       ├── ci.yml
│       ├── claude-dedupe-issues.yml
│       ├── claude-docs-trigger.yml
│       ├── claude-docs-updater.yml
│       ├── claude-issue-triage.yml
│       ├── claude.yml
│       ├── extension-ci.yml
│       ├── extension-release.yml
│       ├── log-issue-events.yml
│       ├── pre-release.yml
│       ├── release-check.yml
│       ├── release.yml
│       ├── update-models-md.yml
│       └── weekly-metrics-discord.yml
├── .gitignore
├── .kiro
│   ├── hooks
│   │   ├── tm-code-change-task-tracker.kiro.hook
│   │   ├── tm-complexity-analyzer.kiro.hook
│   │   ├── tm-daily-standup-assistant.kiro.hook
│   │   ├── tm-git-commit-task-linker.kiro.hook
│   │   ├── tm-pr-readiness-checker.kiro.hook
│   │   ├── tm-task-dependency-auto-progression.kiro.hook
│   │   └── tm-test-success-task-completer.kiro.hook
│   ├── settings
│   │   └── mcp.json
│   └── steering
│       ├── dev_workflow.md
│       ├── kiro_rules.md
│       ├── self_improve.md
│       ├── taskmaster_hooks_workflow.md
│       └── taskmaster.md
├── .manypkg.json
├── .mcp.json
├── .npmignore
├── .nvmrc
├── .taskmaster
│   ├── CLAUDE.md
│   ├── config.json
│   ├── docs
│   │   ├── autonomous-tdd-git-workflow.md
│   │   ├── MIGRATION-ROADMAP.md
│   │   ├── prd-tm-start.txt
│   │   ├── prd.txt
│   │   ├── README.md
│   │   ├── research
│   │   │   ├── 2025-06-14_how-can-i-improve-the-scope-up-and-scope-down-comm.md
│   │   │   ├── 2025-06-14_should-i-be-using-any-specific-libraries-for-this.md
│   │   │   ├── 2025-06-14_test-save-functionality.md
│   │   │   ├── 2025-06-14_test-the-fix-for-duplicate-saves-final-test.md
│   │   │   └── 2025-08-01_do-we-need-to-add-new-commands-or-can-we-just-weap.md
│   │   ├── task-template-importing-prd.txt
│   │   ├── tdd-workflow-phase-0-spike.md
│   │   ├── tdd-workflow-phase-1-core-rails.md
│   │   ├── tdd-workflow-phase-1-orchestrator.md
│   │   ├── tdd-workflow-phase-2-pr-resumability.md
│   │   ├── tdd-workflow-phase-3-extensibility-guardrails.md
│   │   ├── test-prd.txt
│   │   └── tm-core-phase-1.txt
│   ├── reports
│   │   ├── task-complexity-report_autonomous-tdd-git-workflow.json
│   │   ├── task-complexity-report_cc-kiro-hooks.json
│   │   ├── task-complexity-report_tdd-phase-1-core-rails.json
│   │   ├── task-complexity-report_tdd-workflow-phase-0.json
│   │   ├── task-complexity-report_test-prd-tag.json
│   │   ├── task-complexity-report_tm-core-phase-1.json
│   │   ├── task-complexity-report.json
│   │   └── tm-core-complexity.json
│   ├── state.json
│   ├── tasks
│   │   ├── task_001_tm-start.txt
│   │   ├── task_002_tm-start.txt
│   │   ├── task_003_tm-start.txt
│   │   ├── task_004_tm-start.txt
│   │   ├── task_007_tm-start.txt
│   │   └── tasks.json
│   └── templates
│       ├── example_prd_rpg.md
│       └── example_prd.md
├── .vscode
│   ├── extensions.json
│   └── settings.json
├── apps
│   ├── cli
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── command-registry.ts
│   │   │   ├── commands
│   │   │   │   ├── auth.command.ts
│   │   │   │   ├── autopilot
│   │   │   │   │   ├── abort.command.ts
│   │   │   │   │   ├── commit.command.ts
│   │   │   │   │   ├── complete.command.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── next.command.ts
│   │   │   │   │   ├── resume.command.ts
│   │   │   │   │   ├── shared.ts
│   │   │   │   │   ├── start.command.ts
│   │   │   │   │   └── status.command.ts
│   │   │   │   ├── briefs.command.ts
│   │   │   │   ├── context.command.ts
│   │   │   │   ├── export.command.ts
│   │   │   │   ├── list.command.ts
│   │   │   │   ├── models
│   │   │   │   │   ├── custom-providers.ts
│   │   │   │   │   ├── fetchers.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── prompts.ts
│   │   │   │   │   ├── setup.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── next.command.ts
│   │   │   │   ├── set-status.command.ts
│   │   │   │   ├── show.command.ts
│   │   │   │   ├── start.command.ts
│   │   │   │   └── tags.command.ts
│   │   │   ├── index.ts
│   │   │   ├── lib
│   │   │   │   └── model-management.ts
│   │   │   ├── types
│   │   │   │   └── tag-management.d.ts
│   │   │   ├── ui
│   │   │   │   ├── components
│   │   │   │   │   ├── cardBox.component.ts
│   │   │   │   │   ├── dashboard.component.ts
│   │   │   │   │   ├── header.component.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── next-task.component.ts
│   │   │   │   │   ├── suggested-steps.component.ts
│   │   │   │   │   └── task-detail.component.ts
│   │   │   │   ├── display
│   │   │   │   │   ├── messages.ts
│   │   │   │   │   └── tables.ts
│   │   │   │   ├── formatters
│   │   │   │   │   ├── complexity-formatters.ts
│   │   │   │   │   ├── dependency-formatters.ts
│   │   │   │   │   ├── priority-formatters.ts
│   │   │   │   │   ├── status-formatters.spec.ts
│   │   │   │   │   └── status-formatters.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── layout
│   │   │   │       ├── helpers.spec.ts
│   │   │   │       └── helpers.ts
│   │   │   └── utils
│   │   │       ├── auth-helpers.ts
│   │   │       ├── auto-update.ts
│   │   │       ├── brief-selection.ts
│   │   │       ├── display-helpers.ts
│   │   │       ├── error-handler.ts
│   │   │       ├── index.ts
│   │   │       ├── project-root.ts
│   │   │       ├── task-status.ts
│   │   │       ├── ui.spec.ts
│   │   │       └── ui.ts
│   │   ├── tests
│   │   │   ├── integration
│   │   │   │   └── commands
│   │   │   │       └── autopilot
│   │   │   │           └── workflow.test.ts
│   │   │   └── unit
│   │   │       ├── commands
│   │   │       │   ├── autopilot
│   │   │       │   │   └── shared.test.ts
│   │   │       │   ├── list.command.spec.ts
│   │   │       │   └── show.command.spec.ts
│   │   │       └── ui
│   │   │           └── dashboard.component.spec.ts
│   │   ├── tsconfig.json
│   │   └── vitest.config.ts
│   ├── docs
│   │   ├── archive
│   │   │   ├── ai-client-utils-example.mdx
│   │   │   ├── ai-development-workflow.mdx
│   │   │   ├── command-reference.mdx
│   │   │   ├── configuration.mdx
│   │   │   ├── cursor-setup.mdx
│   │   │   ├── examples.mdx
│   │   │   └── Installation.mdx
│   │   ├── best-practices
│   │   │   ├── advanced-tasks.mdx
│   │   │   ├── configuration-advanced.mdx
│   │   │   └── index.mdx
│   │   ├── capabilities
│   │   │   ├── cli-root-commands.mdx
│   │   │   ├── index.mdx
│   │   │   ├── mcp.mdx
│   │   │   ├── rpg-method.mdx
│   │   │   └── task-structure.mdx
│   │   ├── CHANGELOG.md
│   │   ├── command-reference.mdx
│   │   ├── configuration.mdx
│   │   ├── docs.json
│   │   ├── favicon.svg
│   │   ├── getting-started
│   │   │   ├── api-keys.mdx
│   │   │   ├── contribute.mdx
│   │   │   ├── faq.mdx
│   │   │   └── quick-start
│   │   │       ├── configuration-quick.mdx
│   │   │       ├── execute-quick.mdx
│   │   │       ├── installation.mdx
│   │   │       ├── moving-forward.mdx
│   │   │       ├── prd-quick.mdx
│   │   │       ├── quick-start.mdx
│   │   │       ├── requirements.mdx
│   │   │       ├── rules-quick.mdx
│   │   │       └── tasks-quick.mdx
│   │   ├── introduction.mdx
│   │   ├── licensing.md
│   │   ├── logo
│   │   │   ├── dark.svg
│   │   │   ├── light.svg
│   │   │   └── task-master-logo.png
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── style.css
│   │   ├── tdd-workflow
│   │   │   ├── ai-agent-integration.mdx
│   │   │   └── quickstart.mdx
│   │   ├── vercel.json
│   │   └── whats-new.mdx
│   ├── extension
│   │   ├── .vscodeignore
│   │   ├── assets
│   │   │   ├── banner.png
│   │   │   ├── icon-dark.svg
│   │   │   ├── icon-light.svg
│   │   │   ├── icon.png
│   │   │   ├── screenshots
│   │   │   │   ├── kanban-board.png
│   │   │   │   └── task-details.png
│   │   │   └── sidebar-icon.svg
│   │   ├── CHANGELOG.md
│   │   ├── components.json
│   │   ├── docs
│   │   │   ├── extension-CI-setup.md
│   │   │   └── extension-development-guide.md
│   │   ├── esbuild.js
│   │   ├── LICENSE
│   │   ├── package.json
│   │   ├── package.mjs
│   │   ├── package.publish.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── components
│   │   │   │   ├── ConfigView.tsx
│   │   │   │   ├── constants.ts
│   │   │   │   ├── TaskDetails
│   │   │   │   │   ├── AIActionsSection.tsx
│   │   │   │   │   ├── DetailsSection.tsx
│   │   │   │   │   ├── PriorityBadge.tsx
│   │   │   │   │   ├── SubtasksSection.tsx
│   │   │   │   │   ├── TaskMetadataSidebar.tsx
│   │   │   │   │   └── useTaskDetails.ts
│   │   │   │   ├── TaskDetailsView.tsx
│   │   │   │   ├── TaskMasterLogo.tsx
│   │   │   │   └── ui
│   │   │   │       ├── badge.tsx
│   │   │   │       ├── breadcrumb.tsx
│   │   │   │       ├── button.tsx
│   │   │   │       ├── card.tsx
│   │   │   │       ├── collapsible.tsx
│   │   │   │       ├── CollapsibleSection.tsx
│   │   │   │       ├── dropdown-menu.tsx
│   │   │   │       ├── label.tsx
│   │   │   │       ├── scroll-area.tsx
│   │   │   │       ├── separator.tsx
│   │   │   │       ├── shadcn-io
│   │   │   │       │   └── kanban
│   │   │   │       │       └── index.tsx
│   │   │   │       └── textarea.tsx
│   │   │   ├── extension.ts
│   │   │   ├── index.ts
│   │   │   ├── lib
│   │   │   │   └── utils.ts
│   │   │   ├── services
│   │   │   │   ├── config-service.ts
│   │   │   │   ├── error-handler.ts
│   │   │   │   ├── notification-preferences.ts
│   │   │   │   ├── polling-service.ts
│   │   │   │   ├── polling-strategies.ts
│   │   │   │   ├── sidebar-webview-manager.ts
│   │   │   │   ├── task-repository.ts
│   │   │   │   ├── terminal-manager.ts
│   │   │   │   └── webview-manager.ts
│   │   │   ├── test
│   │   │   │   └── extension.test.ts
│   │   │   ├── utils
│   │   │   │   ├── configManager.ts
│   │   │   │   ├── connectionManager.ts
│   │   │   │   ├── errorHandler.ts
│   │   │   │   ├── event-emitter.ts
│   │   │   │   ├── logger.ts
│   │   │   │   ├── mcpClient.ts
│   │   │   │   ├── notificationPreferences.ts
│   │   │   │   └── task-master-api
│   │   │   │       ├── cache
│   │   │   │       │   └── cache-manager.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── mcp-client.ts
│   │   │   │       ├── transformers
│   │   │   │       │   └── task-transformer.ts
│   │   │   │       └── types
│   │   │   │           └── index.ts
│   │   │   └── webview
│   │   │       ├── App.tsx
│   │   │       ├── components
│   │   │       │   ├── AppContent.tsx
│   │   │       │   ├── EmptyState.tsx
│   │   │       │   ├── ErrorBoundary.tsx
│   │   │       │   ├── PollingStatus.tsx
│   │   │       │   ├── PriorityBadge.tsx
│   │   │       │   ├── SidebarView.tsx
│   │   │       │   ├── TagDropdown.tsx
│   │   │       │   ├── TaskCard.tsx
│   │   │       │   ├── TaskEditModal.tsx
│   │   │       │   ├── TaskMasterKanban.tsx
│   │   │       │   ├── ToastContainer.tsx
│   │   │       │   └── ToastNotification.tsx
│   │   │       ├── constants
│   │   │       │   └── index.ts
│   │   │       ├── contexts
│   │   │       │   └── VSCodeContext.tsx
│   │   │       ├── hooks
│   │   │       │   ├── useTaskQueries.ts
│   │   │       │   ├── useVSCodeMessages.ts
│   │   │       │   └── useWebviewHeight.ts
│   │   │       ├── index.css
│   │   │       ├── index.tsx
│   │   │       ├── providers
│   │   │       │   └── QueryProvider.tsx
│   │   │       ├── reducers
│   │   │       │   └── appReducer.ts
│   │   │       ├── sidebar.tsx
│   │   │       ├── types
│   │   │       │   └── index.ts
│   │   │       └── utils
│   │   │           ├── logger.ts
│   │   │           └── toast.ts
│   │   └── tsconfig.json
│   └── mcp
│       ├── CHANGELOG.md
│       ├── package.json
│       ├── src
│       │   ├── index.ts
│       │   ├── shared
│       │   │   ├── types.ts
│       │   │   └── utils.ts
│       │   └── tools
│       │       ├── autopilot
│       │       │   ├── abort.tool.ts
│       │       │   ├── commit.tool.ts
│       │       │   ├── complete.tool.ts
│       │       │   ├── finalize.tool.ts
│       │       │   ├── index.ts
│       │       │   ├── next.tool.ts
│       │       │   ├── resume.tool.ts
│       │       │   ├── start.tool.ts
│       │       │   └── status.tool.ts
│       │       ├── README-ZOD-V3.md
│       │       └── tasks
│       │           ├── get-task.tool.ts
│       │           ├── get-tasks.tool.ts
│       │           └── index.ts
│       ├── tsconfig.json
│       └── vitest.config.ts
├── assets
│   ├── .windsurfrules
│   ├── AGENTS.md
│   ├── claude
│   │   └── TM_COMMANDS_GUIDE.md
│   ├── config.json
│   ├── env.example
│   ├── example_prd_rpg.txt
│   ├── example_prd.txt
│   ├── GEMINI.md
│   ├── gitignore
│   ├── kiro-hooks
│   │   ├── tm-code-change-task-tracker.kiro.hook
│   │   ├── tm-complexity-analyzer.kiro.hook
│   │   ├── tm-daily-standup-assistant.kiro.hook
│   │   ├── tm-git-commit-task-linker.kiro.hook
│   │   ├── tm-pr-readiness-checker.kiro.hook
│   │   ├── tm-task-dependency-auto-progression.kiro.hook
│   │   └── tm-test-success-task-completer.kiro.hook
│   ├── roocode
│   │   ├── .roo
│   │   │   ├── rules-architect
│   │   │   │   └── architect-rules
│   │   │   ├── rules-ask
│   │   │   │   └── ask-rules
│   │   │   ├── rules-code
│   │   │   │   └── code-rules
│   │   │   ├── rules-debug
│   │   │   │   └── debug-rules
│   │   │   ├── rules-orchestrator
│   │   │   │   └── orchestrator-rules
│   │   │   └── rules-test
│   │   │       └── test-rules
│   │   └── .roomodes
│   ├── rules
│   │   ├── cursor_rules.mdc
│   │   ├── dev_workflow.mdc
│   │   ├── self_improve.mdc
│   │   ├── taskmaster_hooks_workflow.mdc
│   │   └── taskmaster.mdc
│   └── scripts_README.md
├── bin
│   └── task-master.js
├── biome.json
├── CHANGELOG.md
├── CLAUDE_CODE_PLUGIN.md
├── CLAUDE.md
├── context
│   ├── chats
│   │   ├── add-task-dependencies-1.md
│   │   └── max-min-tokens.txt.md
│   ├── fastmcp-core.txt
│   ├── fastmcp-docs.txt
│   ├── MCP_INTEGRATION.md
│   ├── mcp-js-sdk-docs.txt
│   ├── mcp-protocol-repo.txt
│   ├── mcp-protocol-schema-03262025.json
│   └── mcp-protocol-spec.txt
├── CONTRIBUTING.md
├── docs
│   ├── claude-code-integration.md
│   ├── CLI-COMMANDER-PATTERN.md
│   ├── command-reference.md
│   ├── configuration.md
│   ├── contributor-docs
│   │   ├── testing-roo-integration.md
│   │   └── worktree-setup.md
│   ├── cross-tag-task-movement.md
│   ├── examples
│   │   ├── claude-code-usage.md
│   │   └── codex-cli-usage.md
│   ├── examples.md
│   ├── licensing.md
│   ├── mcp-provider-guide.md
│   ├── mcp-provider.md
│   ├── migration-guide.md
│   ├── models.md
│   ├── providers
│   │   ├── codex-cli.md
│   │   └── gemini-cli.md
│   ├── README.md
│   ├── scripts
│   │   └── models-json-to-markdown.js
│   ├── task-structure.md
│   └── tutorial.md
├── images
│   ├── hamster-hiring.png
│   └── logo.png
├── index.js
├── jest.config.js
├── jest.resolver.cjs
├── LICENSE
├── llms-install.md
├── mcp-server
│   ├── server.js
│   └── src
│       ├── core
│       │   ├── __tests__
│       │   │   └── context-manager.test.js
│       │   ├── context-manager.js
│       │   ├── direct-functions
│       │   │   ├── add-dependency.js
│       │   │   ├── add-subtask.js
│       │   │   ├── add-tag.js
│       │   │   ├── add-task.js
│       │   │   ├── analyze-task-complexity.js
│       │   │   ├── cache-stats.js
│       │   │   ├── clear-subtasks.js
│       │   │   ├── complexity-report.js
│       │   │   ├── copy-tag.js
│       │   │   ├── create-tag-from-branch.js
│       │   │   ├── delete-tag.js
│       │   │   ├── expand-all-tasks.js
│       │   │   ├── expand-task.js
│       │   │   ├── fix-dependencies.js
│       │   │   ├── generate-task-files.js
│       │   │   ├── initialize-project.js
│       │   │   ├── list-tags.js
│       │   │   ├── models.js
│       │   │   ├── move-task-cross-tag.js
│       │   │   ├── move-task.js
│       │   │   ├── next-task.js
│       │   │   ├── parse-prd.js
│       │   │   ├── remove-dependency.js
│       │   │   ├── remove-subtask.js
│       │   │   ├── remove-task.js
│       │   │   ├── rename-tag.js
│       │   │   ├── research.js
│       │   │   ├── response-language.js
│       │   │   ├── rules.js
│       │   │   ├── scope-down.js
│       │   │   ├── scope-up.js
│       │   │   ├── set-task-status.js
│       │   │   ├── update-subtask-by-id.js
│       │   │   ├── update-task-by-id.js
│       │   │   ├── update-tasks.js
│       │   │   ├── use-tag.js
│       │   │   └── validate-dependencies.js
│       │   ├── task-master-core.js
│       │   └── utils
│       │       ├── env-utils.js
│       │       └── path-utils.js
│       ├── custom-sdk
│       │   ├── errors.js
│       │   ├── index.js
│       │   ├── json-extractor.js
│       │   ├── language-model.js
│       │   ├── message-converter.js
│       │   └── schema-converter.js
│       ├── index.js
│       ├── logger.js
│       ├── providers
│       │   └── mcp-provider.js
│       └── tools
│           ├── add-dependency.js
│           ├── add-subtask.js
│           ├── add-tag.js
│           ├── add-task.js
│           ├── analyze.js
│           ├── clear-subtasks.js
│           ├── complexity-report.js
│           ├── copy-tag.js
│           ├── delete-tag.js
│           ├── expand-all.js
│           ├── expand-task.js
│           ├── fix-dependencies.js
│           ├── generate.js
│           ├── get-operation-status.js
│           ├── index.js
│           ├── initialize-project.js
│           ├── list-tags.js
│           ├── models.js
│           ├── move-task.js
│           ├── next-task.js
│           ├── parse-prd.js
│           ├── README-ZOD-V3.md
│           ├── remove-dependency.js
│           ├── remove-subtask.js
│           ├── remove-task.js
│           ├── rename-tag.js
│           ├── research.js
│           ├── response-language.js
│           ├── rules.js
│           ├── scope-down.js
│           ├── scope-up.js
│           ├── set-task-status.js
│           ├── tool-registry.js
│           ├── update-subtask.js
│           ├── update-task.js
│           ├── update.js
│           ├── use-tag.js
│           ├── utils.js
│           └── validate-dependencies.js
├── mcp-test.js
├── output.json
├── package-lock.json
├── package.json
├── packages
│   ├── ai-sdk-provider-grok-cli
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── errors.test.ts
│   │   │   ├── errors.ts
│   │   │   ├── grok-cli-language-model.ts
│   │   │   ├── grok-cli-provider.test.ts
│   │   │   ├── grok-cli-provider.ts
│   │   │   ├── index.ts
│   │   │   ├── json-extractor.test.ts
│   │   │   ├── json-extractor.ts
│   │   │   ├── message-converter.test.ts
│   │   │   ├── message-converter.ts
│   │   │   └── types.ts
│   │   └── tsconfig.json
│   ├── build-config
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── src
│   │   │   └── tsdown.base.ts
│   │   └── tsconfig.json
│   ├── claude-code-plugin
│   │   ├── .claude-plugin
│   │   │   └── plugin.json
│   │   ├── .gitignore
│   │   ├── agents
│   │   │   ├── task-checker.md
│   │   │   ├── task-executor.md
│   │   │   └── task-orchestrator.md
│   │   ├── CHANGELOG.md
│   │   ├── commands
│   │   │   ├── add-dependency.md
│   │   │   ├── add-subtask.md
│   │   │   ├── add-task.md
│   │   │   ├── analyze-complexity.md
│   │   │   ├── analyze-project.md
│   │   │   ├── auto-implement-tasks.md
│   │   │   ├── command-pipeline.md
│   │   │   ├── complexity-report.md
│   │   │   ├── convert-task-to-subtask.md
│   │   │   ├── expand-all-tasks.md
│   │   │   ├── expand-task.md
│   │   │   ├── fix-dependencies.md
│   │   │   ├── generate-tasks.md
│   │   │   ├── help.md
│   │   │   ├── init-project-quick.md
│   │   │   ├── init-project.md
│   │   │   ├── install-taskmaster.md
│   │   │   ├── learn.md
│   │   │   ├── list-tasks-by-status.md
│   │   │   ├── list-tasks-with-subtasks.md
│   │   │   ├── list-tasks.md
│   │   │   ├── next-task.md
│   │   │   ├── parse-prd-with-research.md
│   │   │   ├── parse-prd.md
│   │   │   ├── project-status.md
│   │   │   ├── quick-install-taskmaster.md
│   │   │   ├── remove-all-subtasks.md
│   │   │   ├── remove-dependency.md
│   │   │   ├── remove-subtask.md
│   │   │   ├── remove-subtasks.md
│   │   │   ├── remove-task.md
│   │   │   ├── setup-models.md
│   │   │   ├── show-task.md
│   │   │   ├── smart-workflow.md
│   │   │   ├── sync-readme.md
│   │   │   ├── tm-main.md
│   │   │   ├── to-cancelled.md
│   │   │   ├── to-deferred.md
│   │   │   ├── to-done.md
│   │   │   ├── to-in-progress.md
│   │   │   ├── to-pending.md
│   │   │   ├── to-review.md
│   │   │   ├── update-single-task.md
│   │   │   ├── update-task.md
│   │   │   ├── update-tasks-from-id.md
│   │   │   ├── validate-dependencies.md
│   │   │   └── view-models.md
│   │   ├── mcp.json
│   │   └── package.json
│   ├── tm-bridge
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── add-tag-bridge.ts
│   │   │   ├── bridge-types.ts
│   │   │   ├── bridge-utils.ts
│   │   │   ├── expand-bridge.ts
│   │   │   ├── index.ts
│   │   │   ├── tags-bridge.ts
│   │   │   ├── update-bridge.ts
│   │   │   └── use-tag-bridge.ts
│   │   └── tsconfig.json
│   └── tm-core
│       ├── .gitignore
│       ├── CHANGELOG.md
│       ├── docs
│       │   └── listTasks-architecture.md
│       ├── package.json
│       ├── POC-STATUS.md
│       ├── README.md
│       ├── src
│       │   ├── common
│       │   │   ├── constants
│       │   │   │   ├── index.ts
│       │   │   │   ├── paths.ts
│       │   │   │   └── providers.ts
│       │   │   ├── errors
│       │   │   │   ├── index.ts
│       │   │   │   └── task-master-error.ts
│       │   │   ├── interfaces
│       │   │   │   ├── configuration.interface.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── storage.interface.ts
│       │   │   ├── logger
│       │   │   │   ├── factory.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── logger.spec.ts
│       │   │   │   └── logger.ts
│       │   │   ├── mappers
│       │   │   │   ├── TaskMapper.test.ts
│       │   │   │   └── TaskMapper.ts
│       │   │   ├── types
│       │   │   │   ├── database.types.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── legacy.ts
│       │   │   │   └── repository-types.ts
│       │   │   └── utils
│       │   │       ├── git-utils.ts
│       │   │       ├── id-generator.ts
│       │   │       ├── index.ts
│       │   │       ├── path-helpers.ts
│       │   │       ├── path-normalizer.spec.ts
│       │   │       ├── path-normalizer.ts
│       │   │       ├── project-root-finder.spec.ts
│       │   │       ├── project-root-finder.ts
│       │   │       ├── run-id-generator.spec.ts
│       │   │       └── run-id-generator.ts
│       │   ├── index.ts
│       │   ├── modules
│       │   │   ├── ai
│       │   │   │   ├── index.ts
│       │   │   │   ├── interfaces
│       │   │   │   │   └── ai-provider.interface.ts
│       │   │   │   └── providers
│       │   │   │       ├── base-provider.ts
│       │   │   │       └── index.ts
│       │   │   ├── auth
│       │   │   │   ├── auth-domain.spec.ts
│       │   │   │   ├── auth-domain.ts
│       │   │   │   ├── config.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── managers
│       │   │   │   │   ├── auth-manager.spec.ts
│       │   │   │   │   └── auth-manager.ts
│       │   │   │   ├── services
│       │   │   │   │   ├── context-store.ts
│       │   │   │   │   ├── oauth-service.ts
│       │   │   │   │   ├── organization.service.ts
│       │   │   │   │   ├── supabase-session-storage.spec.ts
│       │   │   │   │   └── supabase-session-storage.ts
│       │   │   │   └── types.ts
│       │   │   ├── briefs
│       │   │   │   ├── briefs-domain.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── services
│       │   │   │   │   └── brief-service.ts
│       │   │   │   ├── types.ts
│       │   │   │   └── utils
│       │   │   │       └── url-parser.ts
│       │   │   ├── commands
│       │   │   │   └── index.ts
│       │   │   ├── config
│       │   │   │   ├── config-domain.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── managers
│       │   │   │   │   ├── config-manager.spec.ts
│       │   │   │   │   └── config-manager.ts
│       │   │   │   └── services
│       │   │   │       ├── config-loader.service.spec.ts
│       │   │   │       ├── config-loader.service.ts
│       │   │   │       ├── config-merger.service.spec.ts
│       │   │   │       ├── config-merger.service.ts
│       │   │   │       ├── config-persistence.service.spec.ts
│       │   │   │       ├── config-persistence.service.ts
│       │   │   │       ├── environment-config-provider.service.spec.ts
│       │   │   │       ├── environment-config-provider.service.ts
│       │   │   │       ├── index.ts
│       │   │   │       ├── runtime-state-manager.service.spec.ts
│       │   │   │       └── runtime-state-manager.service.ts
│       │   │   ├── dependencies
│       │   │   │   └── index.ts
│       │   │   ├── execution
│       │   │   │   ├── executors
│       │   │   │   │   ├── base-executor.ts
│       │   │   │   │   ├── claude-executor.ts
│       │   │   │   │   └── executor-factory.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── services
│       │   │   │   │   └── executor-service.ts
│       │   │   │   └── types.ts
│       │   │   ├── git
│       │   │   │   ├── adapters
│       │   │   │   │   ├── git-adapter.test.ts
│       │   │   │   │   └── git-adapter.ts
│       │   │   │   ├── git-domain.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── services
│       │   │   │       ├── branch-name-generator.spec.ts
│       │   │   │       ├── branch-name-generator.ts
│       │   │   │       ├── commit-message-generator.test.ts
│       │   │   │       ├── commit-message-generator.ts
│       │   │   │       ├── scope-detector.test.ts
│       │   │   │       ├── scope-detector.ts
│       │   │   │       ├── template-engine.test.ts
│       │   │   │       └── template-engine.ts
│       │   │   ├── integration
│       │   │   │   ├── clients
│       │   │   │   │   ├── index.ts
│       │   │   │   │   └── supabase-client.ts
│       │   │   │   ├── integration-domain.ts
│       │   │   │   └── services
│       │   │   │       ├── export.service.ts
│       │   │   │       ├── task-expansion.service.ts
│       │   │   │       └── task-retrieval.service.ts
│       │   │   ├── reports
│       │   │   │   ├── index.ts
│       │   │   │   ├── managers
│       │   │   │   │   └── complexity-report-manager.ts
│       │   │   │   └── types.ts
│       │   │   ├── storage
│       │   │   │   ├── adapters
│       │   │   │   │   ├── activity-logger.ts
│       │   │   │   │   ├── api-storage.ts
│       │   │   │   │   └── file-storage
│       │   │   │   │       ├── file-operations.ts
│       │   │   │   │       ├── file-storage.ts
│       │   │   │   │       ├── format-handler.ts
│       │   │   │   │       ├── index.ts
│       │   │   │   │       └── path-resolver.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── services
│       │   │   │   │   └── storage-factory.ts
│       │   │   │   └── utils
│       │   │   │       └── api-client.ts
│       │   │   ├── tasks
│       │   │   │   ├── entities
│       │   │   │   │   └── task.entity.ts
│       │   │   │   ├── parser
│       │   │   │   │   └── index.ts
│       │   │   │   ├── repositories
│       │   │   │   │   ├── supabase
│       │   │   │   │   │   ├── dependency-fetcher.ts
│       │   │   │   │   │   ├── index.ts
│       │   │   │   │   │   └── supabase-repository.ts
│       │   │   │   │   └── task-repository.interface.ts
│       │   │   │   ├── services
│       │   │   │   │   ├── preflight-checker.service.ts
│       │   │   │   │   ├── tag.service.ts
│       │   │   │   │   ├── task-execution-service.ts
│       │   │   │   │   ├── task-loader.service.ts
│       │   │   │   │   └── task-service.ts
│       │   │   │   └── tasks-domain.ts
│       │   │   ├── ui
│       │   │   │   └── index.ts
│       │   │   └── workflow
│       │   │       ├── managers
│       │   │       │   ├── workflow-state-manager.spec.ts
│       │   │       │   └── workflow-state-manager.ts
│       │   │       ├── orchestrators
│       │   │       │   ├── workflow-orchestrator.test.ts
│       │   │       │   └── workflow-orchestrator.ts
│       │   │       ├── services
│       │   │       │   ├── test-result-validator.test.ts
│       │   │       │   ├── test-result-validator.ts
│       │   │       │   ├── test-result-validator.types.ts
│       │   │       │   ├── workflow-activity-logger.ts
│       │   │       │   └── workflow.service.ts
│       │   │       ├── types.ts
│       │   │       └── workflow-domain.ts
│       │   ├── subpath-exports.test.ts
│       │   ├── tm-core.ts
│       │   └── utils
│       │       └── time.utils.ts
│       ├── tests
│       │   ├── auth
│       │   │   └── auth-refresh.test.ts
│       │   ├── integration
│       │   │   ├── auth-token-refresh.test.ts
│       │   │   ├── list-tasks.test.ts
│       │   │   └── storage
│       │   │       └── activity-logger.test.ts
│       │   ├── mocks
│       │   │   └── mock-provider.ts
│       │   ├── setup.ts
│       │   └── unit
│       │       ├── base-provider.test.ts
│       │       ├── executor.test.ts
│       │       └── smoke.test.ts
│       ├── tsconfig.json
│       └── vitest.config.ts
├── README-task-master.md
├── README.md
├── scripts
│   ├── create-worktree.sh
│   ├── dev.js
│   ├── init.js
│   ├── list-worktrees.sh
│   ├── modules
│   │   ├── ai-services-unified.js
│   │   ├── bridge-utils.js
│   │   ├── commands.js
│   │   ├── config-manager.js
│   │   ├── dependency-manager.js
│   │   ├── index.js
│   │   ├── prompt-manager.js
│   │   ├── supported-models.json
│   │   ├── sync-readme.js
│   │   ├── task-manager
│   │   │   ├── add-subtask.js
│   │   │   ├── add-task.js
│   │   │   ├── analyze-task-complexity.js
│   │   │   ├── clear-subtasks.js
│   │   │   ├── expand-all-tasks.js
│   │   │   ├── expand-task.js
│   │   │   ├── find-next-task.js
│   │   │   ├── generate-task-files.js
│   │   │   ├── is-task-dependent.js
│   │   │   ├── list-tasks.js
│   │   │   ├── migrate.js
│   │   │   ├── models.js
│   │   │   ├── move-task.js
│   │   │   ├── parse-prd
│   │   │   │   ├── index.js
│   │   │   │   ├── parse-prd-config.js
│   │   │   │   ├── parse-prd-helpers.js
│   │   │   │   ├── parse-prd-non-streaming.js
│   │   │   │   ├── parse-prd-streaming.js
│   │   │   │   └── parse-prd.js
│   │   │   ├── remove-subtask.js
│   │   │   ├── remove-task.js
│   │   │   ├── research.js
│   │   │   ├── response-language.js
│   │   │   ├── scope-adjustment.js
│   │   │   ├── set-task-status.js
│   │   │   ├── tag-management.js
│   │   │   ├── task-exists.js
│   │   │   ├── update-single-task-status.js
│   │   │   ├── update-subtask-by-id.js
│   │   │   ├── update-task-by-id.js
│   │   │   └── update-tasks.js
│   │   ├── task-manager.js
│   │   ├── ui.js
│   │   ├── update-config-tokens.js
│   │   ├── utils
│   │   │   ├── contextGatherer.js
│   │   │   ├── fuzzyTaskSearch.js
│   │   │   └── git-utils.js
│   │   └── utils.js
│   ├── task-complexity-report.json
│   ├── test-claude-errors.js
│   └── test-claude.js
├── sonar-project.properties
├── src
│   ├── ai-providers
│   │   ├── anthropic.js
│   │   ├── azure.js
│   │   ├── base-provider.js
│   │   ├── bedrock.js
│   │   ├── claude-code.js
│   │   ├── codex-cli.js
│   │   ├── gemini-cli.js
│   │   ├── google-vertex.js
│   │   ├── google.js
│   │   ├── grok-cli.js
│   │   ├── groq.js
│   │   ├── index.js
│   │   ├── lmstudio.js
│   │   ├── ollama.js
│   │   ├── openai-compatible.js
│   │   ├── openai.js
│   │   ├── openrouter.js
│   │   ├── perplexity.js
│   │   ├── xai.js
│   │   ├── zai-coding.js
│   │   └── zai.js
│   ├── constants
│   │   ├── commands.js
│   │   ├── paths.js
│   │   ├── profiles.js
│   │   ├── rules-actions.js
│   │   ├── task-priority.js
│   │   └── task-status.js
│   ├── profiles
│   │   ├── amp.js
│   │   ├── base-profile.js
│   │   ├── claude.js
│   │   ├── cline.js
│   │   ├── codex.js
│   │   ├── cursor.js
│   │   ├── gemini.js
│   │   ├── index.js
│   │   ├── kilo.js
│   │   ├── kiro.js
│   │   ├── opencode.js
│   │   ├── roo.js
│   │   ├── trae.js
│   │   ├── vscode.js
│   │   ├── windsurf.js
│   │   └── zed.js
│   ├── progress
│   │   ├── base-progress-tracker.js
│   │   ├── cli-progress-factory.js
│   │   ├── parse-prd-tracker.js
│   │   ├── progress-tracker-builder.js
│   │   └── tracker-ui.js
│   ├── prompts
│   │   ├── add-task.json
│   │   ├── analyze-complexity.json
│   │   ├── expand-task.json
│   │   ├── parse-prd.json
│   │   ├── README.md
│   │   ├── research.json
│   │   ├── schemas
│   │   │   ├── parameter.schema.json
│   │   │   ├── prompt-template.schema.json
│   │   │   ├── README.md
│   │   │   └── variant.schema.json
│   │   ├── update-subtask.json
│   │   ├── update-task.json
│   │   └── update-tasks.json
│   ├── provider-registry
│   │   └── index.js
│   ├── schemas
│   │   ├── add-task.js
│   │   ├── analyze-complexity.js
│   │   ├── base-schemas.js
│   │   ├── expand-task.js
│   │   ├── parse-prd.js
│   │   ├── registry.js
│   │   ├── update-subtask.js
│   │   ├── update-task.js
│   │   └── update-tasks.js
│   ├── task-master.js
│   ├── ui
│   │   ├── confirm.js
│   │   ├── indicators.js
│   │   └── parse-prd.js
│   └── utils
│       ├── asset-resolver.js
│       ├── create-mcp-config.js
│       ├── format.js
│       ├── getVersion.js
│       ├── logger-utils.js
│       ├── manage-gitignore.js
│       ├── path-utils.js
│       ├── profiles.js
│       ├── rule-transformer.js
│       ├── stream-parser.js
│       └── timeout-manager.js
├── test-clean-tags.js
├── test-config-manager.js
├── test-prd.txt
├── test-tag-functions.js
├── test-version-check-full.js
├── test-version-check.js
├── tests
│   ├── e2e
│   │   ├── e2e_helpers.sh
│   │   ├── parse_llm_output.cjs
│   │   ├── run_e2e.sh
│   │   ├── run_fallback_verification.sh
│   │   └── test_llm_analysis.sh
│   ├── fixtures
│   │   ├── .taskmasterconfig
│   │   ├── sample-claude-response.js
│   │   ├── sample-prd.txt
│   │   └── sample-tasks.js
│   ├── helpers
│   │   └── tool-counts.js
│   ├── integration
│   │   ├── claude-code-error-handling.test.js
│   │   ├── claude-code-optional.test.js
│   │   ├── cli
│   │   │   ├── commands.test.js
│   │   │   ├── complex-cross-tag-scenarios.test.js
│   │   │   └── move-cross-tag.test.js
│   │   ├── manage-gitignore.test.js
│   │   ├── mcp-server
│   │   │   └── direct-functions.test.js
│   │   ├── move-task-cross-tag.integration.test.js
│   │   ├── move-task-simple.integration.test.js
│   │   ├── profiles
│   │   │   ├── amp-init-functionality.test.js
│   │   │   ├── claude-init-functionality.test.js
│   │   │   ├── cline-init-functionality.test.js
│   │   │   ├── codex-init-functionality.test.js
│   │   │   ├── cursor-init-functionality.test.js
│   │   │   ├── gemini-init-functionality.test.js
│   │   │   ├── opencode-init-functionality.test.js
│   │   │   ├── roo-files-inclusion.test.js
│   │   │   ├── roo-init-functionality.test.js
│   │   │   ├── rules-files-inclusion.test.js
│   │   │   ├── trae-init-functionality.test.js
│   │   │   ├── vscode-init-functionality.test.js
│   │   │   └── windsurf-init-functionality.test.js
│   │   └── providers
│   │       └── temperature-support.test.js
│   ├── manual
│   │   ├── progress
│   │   │   ├── parse-prd-analysis.js
│   │   │   ├── test-parse-prd.js
│   │   │   └── TESTING_GUIDE.md
│   │   └── prompts
│   │       ├── prompt-test.js
│   │       └── README.md
│   ├── README.md
│   ├── setup.js
│   └── unit
│       ├── ai-providers
│       │   ├── base-provider.test.js
│       │   ├── claude-code.test.js
│       │   ├── codex-cli.test.js
│       │   ├── gemini-cli.test.js
│       │   ├── lmstudio.test.js
│       │   ├── mcp-components.test.js
│       │   ├── openai-compatible.test.js
│       │   ├── openai.test.js
│       │   ├── provider-registry.test.js
│       │   ├── zai-coding.test.js
│       │   ├── zai-provider.test.js
│       │   ├── zai-schema-introspection.test.js
│       │   └── zai.test.js
│       ├── ai-services-unified.test.js
│       ├── commands.test.js
│       ├── config-manager.test.js
│       ├── config-manager.test.mjs
│       ├── dependency-manager.test.js
│       ├── init.test.js
│       ├── initialize-project.test.js
│       ├── kebab-case-validation.test.js
│       ├── manage-gitignore.test.js
│       ├── mcp
│       │   └── tools
│       │       ├── __mocks__
│       │       │   └── move-task.js
│       │       ├── add-task.test.js
│       │       ├── analyze-complexity.test.js
│       │       ├── expand-all.test.js
│       │       ├── get-tasks.test.js
│       │       ├── initialize-project.test.js
│       │       ├── move-task-cross-tag-options.test.js
│       │       ├── move-task-cross-tag.test.js
│       │       ├── remove-task.test.js
│       │       └── tool-registration.test.js
│       ├── mcp-providers
│       │   ├── mcp-components.test.js
│       │   └── mcp-provider.test.js
│       ├── parse-prd.test.js
│       ├── profiles
│       │   ├── amp-integration.test.js
│       │   ├── claude-integration.test.js
│       │   ├── cline-integration.test.js
│       │   ├── codex-integration.test.js
│       │   ├── cursor-integration.test.js
│       │   ├── gemini-integration.test.js
│       │   ├── kilo-integration.test.js
│       │   ├── kiro-integration.test.js
│       │   ├── mcp-config-validation.test.js
│       │   ├── opencode-integration.test.js
│       │   ├── profile-safety-check.test.js
│       │   ├── roo-integration.test.js
│       │   ├── rule-transformer-cline.test.js
│       │   ├── rule-transformer-cursor.test.js
│       │   ├── rule-transformer-gemini.test.js
│       │   ├── rule-transformer-kilo.test.js
│       │   ├── rule-transformer-kiro.test.js
│       │   ├── rule-transformer-opencode.test.js
│       │   ├── rule-transformer-roo.test.js
│       │   ├── rule-transformer-trae.test.js
│       │   ├── rule-transformer-vscode.test.js
│       │   ├── rule-transformer-windsurf.test.js
│       │   ├── rule-transformer-zed.test.js
│       │   ├── rule-transformer.test.js
│       │   ├── selective-profile-removal.test.js
│       │   ├── subdirectory-support.test.js
│       │   ├── trae-integration.test.js
│       │   ├── vscode-integration.test.js
│       │   ├── windsurf-integration.test.js
│       │   └── zed-integration.test.js
│       ├── progress
│       │   └── base-progress-tracker.test.js
│       ├── prompt-manager.test.js
│       ├── prompts
│       │   ├── expand-task-prompt.test.js
│       │   └── prompt-migration.test.js
│       ├── scripts
│       │   └── modules
│       │       ├── commands
│       │       │   ├── move-cross-tag.test.js
│       │       │   └── README.md
│       │       ├── dependency-manager
│       │       │   ├── circular-dependencies.test.js
│       │       │   ├── cross-tag-dependencies.test.js
│       │       │   └── fix-dependencies-command.test.js
│       │       ├── task-manager
│       │       │   ├── add-subtask.test.js
│       │       │   ├── add-task.test.js
│       │       │   ├── analyze-task-complexity.test.js
│       │       │   ├── clear-subtasks.test.js
│       │       │   ├── complexity-report-tag-isolation.test.js
│       │       │   ├── expand-all-tasks.test.js
│       │       │   ├── expand-task.test.js
│       │       │   ├── find-next-task.test.js
│       │       │   ├── generate-task-files.test.js
│       │       │   ├── list-tasks.test.js
│       │       │   ├── models-baseurl.test.js
│       │       │   ├── move-task-cross-tag.test.js
│       │       │   ├── move-task.test.js
│       │       │   ├── parse-prd-schema.test.js
│       │       │   ├── parse-prd.test.js
│       │       │   ├── remove-subtask.test.js
│       │       │   ├── remove-task.test.js
│       │       │   ├── research.test.js
│       │       │   ├── scope-adjustment.test.js
│       │       │   ├── set-task-status.test.js
│       │       │   ├── setup.js
│       │       │   ├── update-single-task-status.test.js
│       │       │   ├── update-subtask-by-id.test.js
│       │       │   ├── update-task-by-id.test.js
│       │       │   └── update-tasks.test.js
│       │       ├── ui
│       │       │   └── cross-tag-error-display.test.js
│       │       └── utils-tag-aware-paths.test.js
│       ├── task-finder.test.js
│       ├── task-manager
│       │   ├── clear-subtasks.test.js
│       │   ├── move-task.test.js
│       │   ├── tag-boundary.test.js
│       │   └── tag-management.test.js
│       ├── task-master.test.js
│       ├── ui
│       │   └── indicators.test.js
│       ├── ui.test.js
│       ├── utils-strip-ansi.test.js
│       └── utils.test.js
├── tsconfig.json
├── tsdown.config.ts
├── turbo.json
└── update-task-migration-plan.md
```

# Files

--------------------------------------------------------------------------------
/tests/integration/cli/complex-cross-tag-scenarios.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { jest } from '@jest/globals';
  2 | import { execSync } from 'child_process';
  3 | import fs from 'fs';
  4 | import path from 'path';
  5 | import os from 'os';
  6 | import { fileURLToPath } from 'url';
  7 | 
  8 | const __filename = fileURLToPath(import.meta.url);
  9 | const __dirname = path.dirname(__filename);
 10 | 
 11 | describe('Complex Cross-Tag Scenarios', () => {
 12 | 	let testDir;
 13 | 	let tasksPath;
 14 | 
 15 | 	// Define binPath once for the entire test suite
 16 | 	const binPath = path.join(
 17 | 		__dirname,
 18 | 		'..',
 19 | 		'..',
 20 | 		'..',
 21 | 		'dist',
 22 | 		'task-master.js'
 23 | 	);
 24 | 
 25 | 	beforeEach(() => {
 26 | 		// Create test directory in OS temp directory to isolate from project
 27 | 		testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tm-test-'));
 28 | 		process.chdir(testDir);
 29 | 		// Keep integration timings deterministic
 30 | 		process.env.TASKMASTER_SKIP_AUTO_UPDATE = '1';
 31 | 
 32 | 		// Initialize task-master
 33 | 		execSync(`node ${binPath} init --yes`, {
 34 | 			stdio: 'pipe'
 35 | 		});
 36 | 
 37 | 		// Create test tasks with complex dependencies in the correct tagged format
 38 | 		const complexTasks = {
 39 | 			master: {
 40 | 				tasks: [
 41 | 					{
 42 | 						id: 1,
 43 | 						title: 'Setup Project',
 44 | 						description: 'Initialize the project structure',
 45 | 						status: 'done',
 46 | 						priority: 'high',
 47 | 						dependencies: [],
 48 | 						details: 'Create basic project structure',
 49 | 						testStrategy: 'Verify project structure exists',
 50 | 						subtasks: []
 51 | 					},
 52 | 					{
 53 | 						id: 2,
 54 | 						title: 'Database Schema',
 55 | 						description: 'Design and implement database schema',
 56 | 						status: 'pending',
 57 | 						priority: 'high',
 58 | 						dependencies: [1],
 59 | 						details: 'Create database tables and relationships',
 60 | 						testStrategy: 'Run database migrations',
 61 | 						subtasks: [
 62 | 							{
 63 | 								id: '2.1',
 64 | 								title: 'User Table',
 65 | 								description: 'Create user table',
 66 | 								status: 'pending',
 67 | 								priority: 'medium',
 68 | 								dependencies: [],
 69 | 								details: 'Design user table schema',
 70 | 								testStrategy: 'Test user creation'
 71 | 							},
 72 | 							{
 73 | 								id: '2.2',
 74 | 								title: 'Product Table',
 75 | 								description: 'Create product table',
 76 | 								status: 'pending',
 77 | 								priority: 'medium',
 78 | 								dependencies: ['2.1'],
 79 | 								details: 'Design product table schema',
 80 | 								testStrategy: 'Test product creation'
 81 | 							}
 82 | 						]
 83 | 					},
 84 | 					{
 85 | 						id: 3,
 86 | 						title: 'API Development',
 87 | 						description: 'Develop REST API endpoints',
 88 | 						status: 'pending',
 89 | 						priority: 'high',
 90 | 						dependencies: [2],
 91 | 						details: 'Create API endpoints for CRUD operations',
 92 | 						testStrategy: 'Test API endpoints',
 93 | 						subtasks: []
 94 | 					},
 95 | 					{
 96 | 						id: 4,
 97 | 						title: 'Frontend Development',
 98 | 						description: 'Develop user interface',
 99 | 						status: 'pending',
100 | 						priority: 'medium',
101 | 						dependencies: [3],
102 | 						details: 'Create React components and pages',
103 | 						testStrategy: 'Test UI components',
104 | 						subtasks: []
105 | 					},
106 | 					{
107 | 						id: 5,
108 | 						title: 'Testing',
109 | 						description: 'Comprehensive testing',
110 | 						status: 'pending',
111 | 						priority: 'medium',
112 | 						dependencies: [4],
113 | 						details: 'Write unit and integration tests',
114 | 						testStrategy: 'Run test suite',
115 | 						subtasks: []
116 | 					}
117 | 				],
118 | 				metadata: {
119 | 					created: new Date().toISOString(),
120 | 					description: 'Test tasks for complex cross-tag scenarios'
121 | 				}
122 | 			}
123 | 		};
124 | 
125 | 		// Write tasks to file
126 | 		tasksPath = path.join(testDir, '.taskmaster', 'tasks', 'tasks.json');
127 | 		fs.writeFileSync(tasksPath, JSON.stringify(complexTasks, null, 2));
128 | 	});
129 | 
130 | 	afterEach(() => {
131 | 		// Change back to project root before cleanup
132 | 		try {
133 | 			process.chdir(global.projectRoot || path.resolve(__dirname, '../../..'));
134 | 		} catch (error) {
135 | 			// If we can't change directory, try a known safe directory
136 | 			process.chdir(require('os').homedir());
137 | 		}
138 | 
139 | 		// Cleanup test directory
140 | 		if (testDir && fs.existsSync(testDir)) {
141 | 			fs.rmSync(testDir, { recursive: true, force: true });
142 | 		}
143 | 		delete process.env.TASKMASTER_SKIP_AUTO_UPDATE;
144 | 	});
145 | 
146 | 	describe('Circular Dependency Detection', () => {
147 | 		it('should detect and prevent circular dependencies', () => {
148 | 			// Create a circular dependency scenario
149 | 			const circularTasks = {
150 | 				backlog: {
151 | 					tasks: [
152 | 						{
153 | 							id: 1,
154 | 							title: 'Task 1',
155 | 							status: 'pending',
156 | 							dependencies: [2],
157 | 							subtasks: []
158 | 						},
159 | 						{
160 | 							id: 2,
161 | 							title: 'Task 2',
162 | 							status: 'pending',
163 | 							dependencies: [3],
164 | 							subtasks: []
165 | 						},
166 | 						{
167 | 							id: 3,
168 | 							title: 'Task 3',
169 | 							status: 'pending',
170 | 							dependencies: [1],
171 | 							subtasks: []
172 | 						}
173 | 					],
174 | 					metadata: {
175 | 						created: new Date().toISOString(),
176 | 						description: 'Backlog tasks with circular dependencies'
177 | 					}
178 | 				},
179 | 				'in-progress': {
180 | 					tasks: [],
181 | 					metadata: {
182 | 						created: new Date().toISOString(),
183 | 						description: 'In-progress tasks'
184 | 					}
185 | 				}
186 | 			};
187 | 
188 | 			fs.writeFileSync(tasksPath, JSON.stringify(circularTasks, null, 2));
189 | 
190 | 			// Try to move task 1 - should fail due to circular dependency
191 | 			expect(() => {
192 | 				execSync(
193 | 					`node ${binPath} move --from=1 --from-tag=backlog --to-tag=in-progress`,
194 | 					{ stdio: 'pipe' }
195 | 				);
196 | 			}).toThrow();
197 | 
198 | 			// Check that the move was not performed
199 | 			const tasksAfter = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
200 | 			expect(tasksAfter.backlog.tasks.find((t) => t.id === 1)).toBeDefined();
201 | 			expect(
202 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 1)
203 | 			).toBeUndefined();
204 | 		});
205 | 	});
206 | 
207 | 	describe('Complex Dependency Chains', () => {
208 | 		it('should handle deep dependency chains correctly', () => {
209 | 			// Create a deep dependency chain
210 | 			const deepChainTasks = {
211 | 				master: {
212 | 					tasks: [
213 | 						{
214 | 							id: 1,
215 | 							title: 'Task 1',
216 | 							status: 'pending',
217 | 							dependencies: [2],
218 | 							subtasks: []
219 | 						},
220 | 						{
221 | 							id: 2,
222 | 							title: 'Task 2',
223 | 							status: 'pending',
224 | 							dependencies: [3],
225 | 							subtasks: []
226 | 						},
227 | 						{
228 | 							id: 3,
229 | 							title: 'Task 3',
230 | 							status: 'pending',
231 | 							dependencies: [4],
232 | 							subtasks: []
233 | 						},
234 | 						{
235 | 							id: 4,
236 | 							title: 'Task 4',
237 | 							status: 'pending',
238 | 							dependencies: [5],
239 | 							subtasks: []
240 | 						},
241 | 						{
242 | 							id: 5,
243 | 							title: 'Task 5',
244 | 							status: 'pending',
245 | 							dependencies: [],
246 | 							subtasks: []
247 | 						}
248 | 					],
249 | 					metadata: {
250 | 						created: new Date().toISOString(),
251 | 						description: 'Deep dependency chain tasks'
252 | 					}
253 | 				},
254 | 				'in-progress': {
255 | 					tasks: [],
256 | 					metadata: {
257 | 						created: new Date().toISOString(),
258 | 						description: 'In-progress tasks'
259 | 					}
260 | 				}
261 | 			};
262 | 
263 | 			fs.writeFileSync(tasksPath, JSON.stringify(deepChainTasks, null, 2));
264 | 
265 | 			// Move task 1 with dependencies - should move entire chain
266 | 			execSync(
267 | 				`node ${binPath} move --from=1 --from-tag=master --to-tag=in-progress --with-dependencies`,
268 | 				{ stdio: 'pipe' }
269 | 			);
270 | 
271 | 			// Verify all tasks in the chain were moved
272 | 			const tasksAfter = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
273 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 1)).toBeUndefined();
274 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 2)).toBeUndefined();
275 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 3)).toBeUndefined();
276 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 4)).toBeUndefined();
277 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 5)).toBeUndefined();
278 | 
279 | 			expect(
280 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 1)
281 | 			).toBeDefined();
282 | 			expect(
283 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 2)
284 | 			).toBeDefined();
285 | 			expect(
286 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 3)
287 | 			).toBeDefined();
288 | 			expect(
289 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 4)
290 | 			).toBeDefined();
291 | 			expect(
292 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 5)
293 | 			).toBeDefined();
294 | 		});
295 | 	});
296 | 
297 | 	describe('Subtask Movement Restrictions', () => {
298 | 		it('should prevent direct subtask movement between tags', () => {
299 | 			// Try to move a subtask directly
300 | 			expect(() => {
301 | 				execSync(
302 | 					`node ${binPath} move --from=2.1 --from-tag=master --to-tag=in-progress`,
303 | 					{ stdio: 'pipe' }
304 | 				);
305 | 			}).toThrow();
306 | 
307 | 			// Verify subtask was not moved
308 | 			const tasksAfter = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
309 | 			const task2 = tasksAfter.master.tasks.find((t) => t.id === 2);
310 | 			expect(task2).toBeDefined();
311 | 			expect(task2.subtasks.find((s) => s.id === '2.1')).toBeDefined();
312 | 		});
313 | 
314 | 		it('should allow moving parent task with all subtasks', () => {
315 | 			// Move parent task with dependencies (includes subtasks)
316 | 			execSync(
317 | 				`node ${binPath} move --from=2 --from-tag=master --to-tag=in-progress --with-dependencies`,
318 | 				{ stdio: 'pipe' }
319 | 			);
320 | 
321 | 			// Verify parent and subtasks were moved
322 | 			const tasksAfter = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
323 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 2)).toBeUndefined();
324 | 			const movedTask2 = tasksAfter['in-progress'].tasks.find(
325 | 				(t) => t.id === 2
326 | 			);
327 | 			expect(movedTask2).toBeDefined();
328 | 			expect(movedTask2.subtasks).toHaveLength(2);
329 | 		});
330 | 	});
331 | 
332 | 	describe('Large Task Set Performance', () => {
333 | 		it('should handle large task sets efficiently', () => {
334 | 			// Create a large task set (50 tasks)
335 | 			const largeTaskSet = {
336 | 				master: {
337 | 					tasks: [],
338 | 					metadata: {
339 | 						created: new Date().toISOString(),
340 | 						description: 'Large task set for performance testing'
341 | 					}
342 | 				},
343 | 				'in-progress': {
344 | 					tasks: [],
345 | 					metadata: {
346 | 						created: new Date().toISOString(),
347 | 						description: 'In-progress tasks'
348 | 					}
349 | 				}
350 | 			};
351 | 
352 | 			// Add 25 tasks to master with dependencies
353 | 			for (let i = 1; i <= 25; i++) {
354 | 				largeTaskSet.master.tasks.push({
355 | 					id: i,
356 | 					title: `Task ${i}`,
357 | 					status: 'pending',
358 | 					dependencies: i > 1 ? [i - 1] : [],
359 | 					subtasks: []
360 | 				});
361 | 			}
362 | 
363 | 			// Add 25 tasks to in-progress (ensure no ID conflict with master)
364 | 			for (let i = 26; i <= 50; i++) {
365 | 				largeTaskSet['in-progress'].tasks.push({
366 | 					id: i,
367 | 					title: `Task ${i}`,
368 | 					status: 'in-progress',
369 | 					dependencies: [],
370 | 					subtasks: []
371 | 				});
372 | 			}
373 | 
374 | 			fs.writeFileSync(tasksPath, JSON.stringify(largeTaskSet, null, 2));
375 | 			// Execute move; correctness is validated below (no timing assertion)
376 | 			execSync(
377 | 				`node ${binPath} move --from=25 --from-tag=master --to-tag=in-progress --with-dependencies`,
378 | 				{ stdio: 'pipe' }
379 | 			);
380 | 
381 | 			// Verify the move was successful
382 | 			const tasksAfter = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
383 | 
384 | 			// Verify all tasks in the dependency chain were moved
385 | 			for (let i = 1; i <= 25; i++) {
386 | 				expect(tasksAfter.master.tasks.find((t) => t.id === i)).toBeUndefined();
387 | 				expect(
388 | 					tasksAfter['in-progress'].tasks.find((t) => t.id === i)
389 | 				).toBeDefined();
390 | 			}
391 | 
392 | 			// Verify in-progress still has its original tasks (26-50)
393 | 			for (let i = 26; i <= 50; i++) {
394 | 				expect(
395 | 					tasksAfter['in-progress'].tasks.find((t) => t.id === i)
396 | 				).toBeDefined();
397 | 			}
398 | 
399 | 			// Final count check
400 | 			expect(tasksAfter['in-progress'].tasks).toHaveLength(50); // 25 moved + 25 original
401 | 		});
402 | 	});
403 | 
404 | 	describe('Error Recovery and Edge Cases', () => {
405 | 		it('should handle invalid task IDs gracefully', () => {
406 | 			expect(() => {
407 | 				execSync(
408 | 					`node ${binPath} move --from=999 --from-tag=master --to-tag=in-progress`,
409 | 					{ stdio: 'pipe' }
410 | 				);
411 | 			}).toThrow();
412 | 		});
413 | 
414 | 		it('should handle invalid tag names gracefully', () => {
415 | 			expect(() => {
416 | 				execSync(
417 | 					`node ${binPath} move --from=1 --from-tag=invalid-tag --to-tag=in-progress`,
418 | 					{ stdio: 'pipe' }
419 | 				);
420 | 			}).toThrow();
421 | 		});
422 | 
423 | 		it('should handle same source and target tags', () => {
424 | 			expect(() => {
425 | 				execSync(
426 | 					`node ${binPath} move --from=1 --from-tag=master --to-tag=master`,
427 | 					{ stdio: 'pipe' }
428 | 				);
429 | 			}).toThrow();
430 | 		});
431 | 
432 | 		it('should create target tag if it does not exist', () => {
433 | 			execSync(
434 | 				`node ${binPath} move --from=1 --from-tag=master --to-tag=new-tag`,
435 | 				{ stdio: 'pipe' }
436 | 			);
437 | 
438 | 			const tasksAfter = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
439 | 			expect(tasksAfter['new-tag']).toBeDefined();
440 | 			expect(tasksAfter['new-tag'].tasks.find((t) => t.id === 1)).toBeDefined();
441 | 		});
442 | 	});
443 | 
444 | 	describe('Multiple Task Movement', () => {
445 | 		it('should move multiple tasks simultaneously', () => {
446 | 			// Create tasks for multiple movement test
447 | 			const multiTaskSet = {
448 | 				master: {
449 | 					tasks: [
450 | 						{
451 | 							id: 1,
452 | 							title: 'Task 1',
453 | 							status: 'pending',
454 | 							dependencies: [],
455 | 							subtasks: []
456 | 						},
457 | 						{
458 | 							id: 2,
459 | 							title: 'Task 2',
460 | 							status: 'pending',
461 | 							dependencies: [],
462 | 							subtasks: []
463 | 						},
464 | 						{
465 | 							id: 3,
466 | 							title: 'Task 3',
467 | 							status: 'pending',
468 | 							dependencies: [],
469 | 							subtasks: []
470 | 						}
471 | 					],
472 | 					metadata: {
473 | 						created: new Date().toISOString(),
474 | 						description: 'Tasks for multiple movement test'
475 | 					}
476 | 				},
477 | 				'in-progress': {
478 | 					tasks: [],
479 | 					metadata: {
480 | 						created: new Date().toISOString(),
481 | 						description: 'In-progress tasks'
482 | 					}
483 | 				}
484 | 			};
485 | 
486 | 			fs.writeFileSync(tasksPath, JSON.stringify(multiTaskSet, null, 2));
487 | 
488 | 			// Move multiple tasks
489 | 			execSync(
490 | 				`node ${binPath} move --from=1,2,3 --from-tag=master --to-tag=in-progress`,
491 | 				{ stdio: 'pipe' }
492 | 			);
493 | 
494 | 			// Verify all tasks were moved
495 | 			const tasksAfter = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
496 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 1)).toBeUndefined();
497 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 2)).toBeUndefined();
498 | 			expect(tasksAfter.master.tasks.find((t) => t.id === 3)).toBeUndefined();
499 | 
500 | 			expect(
501 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 1)
502 | 			).toBeDefined();
503 | 			expect(
504 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 2)
505 | 			).toBeDefined();
506 | 			expect(
507 | 				tasksAfter['in-progress'].tasks.find((t) => t.id === 3)
508 | 			).toBeDefined();
509 | 		});
510 | 	});
511 | });
512 | 
```

--------------------------------------------------------------------------------
/docs/providers/codex-cli.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Codex CLI Provider
  2 | 
  3 | The `codex-cli` provider integrates Task Master with OpenAI's Codex CLI via the community AI SDK provider [`ai-sdk-provider-codex-cli`](https://github.com/ben-vargas/ai-sdk-provider-codex-cli). It uses your ChatGPT subscription (OAuth) via `codex login`, with optional `OPENAI_CODEX_API_KEY` support.
  4 | 
  5 | ## Why Use Codex CLI?
  6 | 
  7 | The primary benefits of using the `codex-cli` provider include:
  8 | 
  9 | - **Use Latest OpenAI Models**: Access to cutting-edge models like GPT-5 and GPT-5-Codex via ChatGPT subscription
 10 | - **OAuth Authentication**: No API key management needed - authenticate once with `codex login`
 11 | - **Built-in Tool Execution**: Native support for command execution, file changes, MCP tools, and web search
 12 | - **Native JSON Schema Support**: Structured output generation without post-processing
 13 | - **Approval/Sandbox Modes**: Fine-grained control over command execution and filesystem access for safety
 14 | 
 15 | ## Quickstart
 16 | 
 17 | Get up and running with Codex CLI in 3 steps:
 18 | 
 19 | ```bash
 20 | # 1. Install Codex CLI globally
 21 | npm install -g @openai/codex
 22 | 
 23 | # 2. Authenticate with your ChatGPT account
 24 | codex login
 25 | 
 26 | # 3. Configure Task Master to use Codex CLI
 27 | task-master models --set-main gpt-5-codex --codex-cli
 28 | ```
 29 | 
 30 | ## Requirements
 31 | 
 32 | - **Node.js**: >= 18.0.0
 33 | - **Codex CLI**: >= 0.42.0 (>= 0.44.0 recommended)
 34 | - **ChatGPT Subscription**: Required for OAuth access (Plus, Pro, Business, Edu, or Enterprise)
 35 | - **Task Master**: >= 0.27.3 (version with Codex CLI support)
 36 | 
 37 | ### Checking Your Versions
 38 | 
 39 | ```bash
 40 | # Check Node.js version
 41 | node --version
 42 | 
 43 | # Check Codex CLI version
 44 | codex --version
 45 | 
 46 | # Check Task Master version
 47 | task-master --version
 48 | ```
 49 | 
 50 | ## Installation
 51 | 
 52 | ### Install Codex CLI
 53 | 
 54 | ```bash
 55 | # Install globally via npm
 56 | npm install -g @openai/codex
 57 | 
 58 | # Verify installation
 59 | codex --version
 60 | ```
 61 | 
 62 | Expected output: `v0.44.0` or higher
 63 | 
 64 | ### Install Task Master (if not already installed)
 65 | 
 66 | ```bash
 67 | # Install globally
 68 | npm install -g task-master-ai
 69 | 
 70 | # Or install in your project
 71 | npm install --save-dev task-master-ai
 72 | ```
 73 | 
 74 | ## Authentication
 75 | 
 76 | ### OAuth Authentication (Primary Method - Recommended)
 77 | 
 78 | The Codex CLI provider is designed to use OAuth authentication with your ChatGPT subscription:
 79 | 
 80 | ```bash
 81 | # Launch Codex CLI and authenticate
 82 | codex login
 83 | ```
 84 | 
 85 | This will:
 86 | 1. Open a browser window for OAuth authentication
 87 | 2. Prompt you to log in with your ChatGPT account
 88 | 3. Store authentication credentials locally
 89 | 4. Allow Task Master to automatically use these credentials
 90 | 
 91 | To verify your authentication:
 92 | ```bash
 93 | # Open interactive Codex CLI
 94 | codex
 95 | 
 96 | # Use /about command to see auth status
 97 | /about
 98 | ```
 99 | 
100 | ### Optional: API Key Method
101 | 
102 | While OAuth is the primary and recommended method, you can optionally use an OpenAI API key:
103 | 
104 | ```bash
105 | # In your .env file
106 | OPENAI_CODEX_API_KEY=sk-your-openai-api-key-here
107 | ```
108 | 
109 | **Important Notes**:
110 | - The API key will **only** be injected when explicitly provided
111 | - OAuth authentication is always preferred when available
112 | - Using an API key doesn't provide access to subscription-only models like GPT-5-Codex
113 | - For full OpenAI API access with non-subscription models, consider using the standard `openai` provider instead
114 | - `OPENAI_CODEX_API_KEY` is specific to the codex-cli provider to avoid conflicts with the `openai` provider's `OPENAI_API_KEY`
115 | 
116 | ## Available Models
117 | 
118 | The Codex CLI provider supports only models available through ChatGPT subscription:
119 | 
120 | | Model ID | Description | Max Input Tokens | Max Output Tokens |
121 | |----------|-------------|------------------|-------------------|
122 | | `gpt-5` | Latest GPT-5 model | 272K | 128K |
123 | | `gpt-5-codex` | GPT-5 optimized for agentic software engineering | 272K | 128K |
124 | 
125 | **Note**: These models are only available via OAuth subscription through Codex CLI (ChatGPT Plus, Pro, Business, Edu, or Enterprise plans). For other OpenAI models, use the standard `openai` provider with an API key.
126 | 
127 | **Research Capabilities**: Both GPT-5 models support web search tools, making them suitable for the `research` role in addition to `main` and `fallback` roles.
128 | 
129 | ## Configuration
130 | 
131 | ### Basic Configuration
132 | 
133 | Add Codex CLI to your `.taskmaster/config.json`:
134 | 
135 | ```json
136 | {
137 |   "models": {
138 |     "main": {
139 |       "provider": "codex-cli",
140 |       "modelId": "gpt-5-codex",
141 |       "maxTokens": 128000,
142 |       "temperature": 0.2
143 |     },
144 |     "fallback": {
145 |       "provider": "codex-cli",
146 |       "modelId": "gpt-5",
147 |       "maxTokens": 128000,
148 |       "temperature": 0.2
149 |     }
150 |   }
151 | }
152 | ```
153 | 
154 | ### Advanced Configuration with Codex CLI Settings
155 | 
156 | The `codexCli` section allows you to customize Codex CLI behavior:
157 | 
158 | ```json
159 | {
160 |   "models": {
161 |     "main": {
162 |       "provider": "codex-cli",
163 |       "modelId": "gpt-5-codex",
164 |       "maxTokens": 128000,
165 |       "temperature": 0.2
166 |     }
167 |   },
168 |   "codexCli": {
169 |     "allowNpx": true,
170 |     "skipGitRepoCheck": true,
171 |     "approvalMode": "on-failure",
172 |     "sandboxMode": "workspace-write",
173 |     "verbose": false
174 |   }
175 | }
176 | ```
177 | 
178 | ### Codex CLI Settings Reference
179 | 
180 | #### Core Settings
181 | 
182 | - **`allowNpx`** (boolean, default: `false`)
183 |   - Allow fallback to `npx @openai/codex` if the CLI is not found on PATH
184 |   - Useful for CI environments or systems without global npm installations
185 |   - Example: `"allowNpx": true`
186 | 
187 | - **`skipGitRepoCheck`** (boolean, default: `false`)
188 |   - Skip git repository safety check before execution
189 |   - Recommended for CI environments or non-repository usage
190 |   - Example: `"skipGitRepoCheck": true`
191 | 
192 | #### Execution Control
193 | 
194 | - **`approvalMode`** (string)
195 |   - Controls when to require user approval for command execution
196 |   - Options:
197 |     - `"untrusted"`: Require approval for all commands
198 |     - `"on-failure"`: Only require approval after a command fails (default)
199 |     - `"on-request"`: Approve only when explicitly requested
200 |     - `"never"`: Never require approval (use with caution)
201 |   - Example: `"approvalMode": "on-failure"`
202 | 
203 | - **`sandboxMode`** (string)
204 |   - Controls filesystem access permissions
205 |   - Options:
206 |     - `"read-only"`: Read-only access to filesystem
207 |     - `"workspace-write"`: Allow writes to workspace directory (default)
208 |     - `"danger-full-access"`: Full filesystem access (use with extreme caution)
209 |   - Example: `"sandboxMode": "workspace-write"`
210 | 
211 | #### Path and Environment
212 | 
213 | - **`codexPath`** (string, optional)
214 |   - Custom path to Codex CLI executable
215 |   - Useful when Codex is installed in a non-standard location
216 |   - Example: `"codexPath": "/usr/local/bin/codex"`
217 | 
218 | - **`cwd`** (string, optional)
219 |   - Working directory for Codex CLI execution
220 |   - Defaults to current working directory
221 |   - Example: `"cwd": "/path/to/project"`
222 | 
223 | - **`env`** (object, optional)
224 |   - Additional environment variables for Codex CLI
225 |   - Example: `"env": { "DEBUG": "true" }`
226 | 
227 | #### Advanced Settings
228 | 
229 | - **`fullAuto`** (boolean, optional)
230 |   - Fully automatic mode (equivalent to `--full-auto` flag)
231 |   - Bypasses most approvals for fully automated workflows
232 |   - Example: `"fullAuto": true`
233 | 
234 | - **`dangerouslyBypassApprovalsAndSandbox`** (boolean, optional)
235 |   - Bypass all safety checks including approvals and sandbox
236 |   - **WARNING**: Use with extreme caution - can execute arbitrary code
237 |   - Example: `"dangerouslyBypassApprovalsAndSandbox": false`
238 | 
239 | - **`color`** (string, optional)
240 |   - Force color handling in Codex CLI output
241 |   - Options: `"always"`, `"never"`, `"auto"`
242 |   - Example: `"color": "auto"`
243 | 
244 | - **`outputLastMessageFile`** (string, optional)
245 |   - Write last agent message to specified file
246 |   - Useful for debugging or logging
247 |   - Example: `"outputLastMessageFile": "./last-message.txt"`
248 | 
249 | - **`verbose`** (boolean, optional)
250 |   - Enable verbose provider logging
251 |   - Helpful for debugging issues
252 |   - Example: `"verbose": true`
253 | 
254 | ### Command-Specific Settings
255 | 
256 | Override settings for specific Task Master commands:
257 | 
258 | ```json
259 | {
260 |   "codexCli": {
261 |     "allowNpx": true,
262 |     "approvalMode": "on-failure",
263 |     "commandSpecific": {
264 |       "parse-prd": {
265 |         "approvalMode": "never",
266 |         "verbose": true
267 |       },
268 |       "expand": {
269 |         "sandboxMode": "read-only"
270 |       },
271 |       "add-task": {
272 |         "approvalMode": "untrusted"
273 |       }
274 |     }
275 |   }
276 | }
277 | ```
278 | 
279 | ## Usage
280 | 
281 | ### Setting Codex CLI Models
282 | 
283 | ```bash
284 | # Set Codex CLI for main role
285 | task-master models --set-main gpt-5-codex --codex-cli
286 | 
287 | # Set Codex CLI for fallback role
288 | task-master models --set-fallback gpt-5 --codex-cli
289 | 
290 | # Set Codex CLI for research role
291 | task-master models --set-research gpt-5 --codex-cli
292 | 
293 | # Verify configuration
294 | task-master models
295 | ```
296 | 
297 | ### Using Codex CLI with Task Master Commands
298 | 
299 | Once configured, use Task Master commands as normal:
300 | 
301 | ```bash
302 | # Parse a PRD with Codex CLI
303 | task-master parse-prd my-requirements.txt
304 | 
305 | # Analyze project complexity
306 | task-master analyze-complexity --research
307 | 
308 | # Expand a task into subtasks
309 | task-master expand --id=1.2
310 | 
311 | # Add a new task with AI assistance
312 | task-master add-task --prompt="Implement user authentication" --research
313 | ```
314 | 
315 | The provider will automatically use your OAuth credentials when Codex CLI is configured.
316 | 
317 | ## Codebase Features
318 | 
319 | The Codex CLI provider is **codebase-capable**, meaning it can analyze and interact with your project files. This enables advanced features like:
320 | 
321 | - **Code Analysis**: Understanding your project structure and dependencies
322 | - **Intelligent Suggestions**: Context-aware task recommendations
323 | - **File Operations**: Reading and analyzing project files for better task generation
324 | - **Pattern Recognition**: Identifying common patterns and best practices in your codebase
325 | 
326 | ### Enabling Codebase Analysis
327 | 
328 | Codebase analysis is automatically enabled when:
329 | 1. Your provider is set to `codex-cli`
330 | 2. `enableCodebaseAnalysis` is `true` in your global configuration (default)
331 | 
332 | To verify or configure:
333 | 
334 | ```json
335 | {
336 |   "global": {
337 |     "enableCodebaseAnalysis": true
338 |   }
339 | }
340 | ```
341 | 
342 | ## Troubleshooting
343 | 
344 | ### "codex: command not found" Error
345 | 
346 | **Symptoms**: Task Master reports that the Codex CLI is not found.
347 | 
348 | **Solutions**:
349 | 1. **Install Codex CLI globally**:
350 |    ```bash
351 |    npm install -g @openai/codex
352 |    ```
353 | 
354 | 2. **Verify installation**:
355 |    ```bash
356 |    codex --version
357 |    ```
358 | 
359 | 3. **Alternative: Enable npx fallback**:
360 |    ```json
361 |    {
362 |      "codexCli": {
363 |        "allowNpx": true
364 |      }
365 |    }
366 |    ```
367 | 
368 | ### "Not logged in" Errors
369 | 
370 | **Symptoms**: Authentication errors when trying to use Codex CLI.
371 | 
372 | **Solutions**:
373 | 1. **Authenticate with OAuth**:
374 |    ```bash
375 |    codex login
376 |    ```
377 | 
378 | 2. **Verify authentication status**:
379 |    ```bash
380 |    codex
381 |    # Then use /about command
382 |    ```
383 | 
384 | 3. **Re-authenticate if needed**:
385 |    ```bash
386 |    # Logout first
387 |    codex
388 |    # Use /auth command to change auth method
389 | 
390 |    # Then login again
391 |    codex login
392 |    ```
393 | 
394 | ### "Old version" Warnings
395 | 
396 | **Symptoms**: Warnings about Codex CLI version being outdated.
397 | 
398 | **Solutions**:
399 | 1. **Check current version**:
400 |    ```bash
401 |    codex --version
402 |    ```
403 | 
404 | 2. **Upgrade to latest version**:
405 |    ```bash
406 |    npm install -g @openai/codex@latest
407 |    ```
408 | 
409 | 3. **Verify upgrade**:
410 |    ```bash
411 |    codex --version
412 |    ```
413 |    Should show >= 0.44.0
414 | 
415 | ### "Model not available" Errors
416 | 
417 | **Symptoms**: Error indicating the requested model is not available.
418 | 
419 | **Causes and Solutions**:
420 | 
421 | 1. **Using unsupported model**:
422 |    - Only `gpt-5` and `gpt-5-codex` are available via Codex CLI
423 |    - For other OpenAI models, use the standard `openai` provider
424 | 
425 | 2. **Subscription not active**:
426 |    - Verify your ChatGPT subscription is active
427 |    - Check subscription status at <https://platform.openai.com>
428 | 
429 | 3. **Wrong provider selected**:
430 |    - Verify you're using `--codex-cli` flag when setting models
431 |    - Check `.taskmaster/config.json` shows `"provider": "codex-cli"`
432 | 
433 | ### API Key Not Being Used
434 | 
435 | **Symptoms**: You've set `OPENAI_CODEX_API_KEY` but it's not being used.
436 | 
437 | **Expected Behavior**:
438 | - OAuth authentication is always preferred
439 | - API key is only injected when explicitly provided
440 | - API key doesn't grant access to subscription-only models
441 | 
442 | **Solutions**:
443 | 1. **Verify OAuth is working**:
444 |    ```bash
445 |    codex
446 |    # Check /about for auth status
447 |    ```
448 | 
449 | 2. **If you want to force API key usage**:
450 |    - This is not recommended with Codex CLI
451 |    - Consider using the standard `openai` provider instead
452 | 
453 | 3. **Verify .env file is being loaded**:
454 |    ```bash
455 |    # Check if .env exists in project root
456 |    ls -la .env
457 | 
458 |    # Verify OPENAI_CODEX_API_KEY is set
459 |    grep OPENAI_CODEX_API_KEY .env
460 |    ```
461 | 
462 | ### Approval/Sandbox Issues
463 | 
464 | **Symptoms**: Commands are blocked or filesystem access is denied.
465 | 
466 | **Solutions**:
467 | 
468 | 1. **Adjust approval mode**:
469 |    ```json
470 |    {
471 |      "codexCli": {
472 |        "approvalMode": "on-request"
473 |      }
474 |    }
475 |    ```
476 | 
477 | 2. **Adjust sandbox mode**:
478 |    ```json
479 |    {
480 |      "codexCli": {
481 |        "sandboxMode": "workspace-write"
482 |      }
483 |    }
484 |    ```
485 | 
486 | 3. **For fully automated workflows** (use cautiously):
487 |    ```json
488 |    {
489 |      "codexCli": {
490 |        "fullAuto": true
491 |      }
492 |    }
493 |    ```
494 | 
495 | ## Important Notes
496 | 
497 | - **OAuth subscription required**: No API key needed for basic operation, but requires active ChatGPT subscription
498 | - **Limited model selection**: Only `gpt-5` and `gpt-5-codex` available via OAuth
499 | - **Pricing information**: Not available for OAuth models (shows as "Unknown" in cost calculations)
500 | - **No automatic dependency**: The `@openai/codex` package is not added to Task Master's dependencies - install it globally or enable `allowNpx`
501 | - **Codebase analysis**: Automatically enabled when using `codex-cli` provider
502 | - **Safety first**: Default settings prioritize safety with `approvalMode: "on-failure"` and `sandboxMode: "workspace-write"`
503 | 
504 | ## See Also
505 | 
506 | - [Configuration Guide](../configuration.md#codex-cli-provider) - Complete Codex CLI configuration reference
507 | - [Command Reference](../command-reference.md) - Using `--codex-cli` flag with commands
508 | - [Gemini CLI Provider](./gemini-cli.md) - Similar CLI-based provider for Google Gemini
509 | - [Claude Code Integration](../claude-code-integration.md) - Another CLI-based provider
510 | - [ai-sdk-provider-codex-cli](https://github.com/ben-vargas/ai-sdk-provider-codex-cli) - Source code for the provider package
511 | 
```

--------------------------------------------------------------------------------
/scripts/modules/task-manager/update-subtask-by-id.js:
--------------------------------------------------------------------------------

```javascript
  1 | import fs from 'fs';
  2 | import path from 'path';
  3 | import chalk from 'chalk';
  4 | import boxen from 'boxen';
  5 | import Table from 'cli-table3';
  6 | 
  7 | import {
  8 | 	getStatusWithColor,
  9 | 	startLoadingIndicator,
 10 | 	stopLoadingIndicator,
 11 | 	displayAiUsageSummary
 12 | } from '../ui.js';
 13 | import {
 14 | 	log as consoleLog,
 15 | 	readJSON,
 16 | 	writeJSON,
 17 | 	truncate,
 18 | 	isSilentMode,
 19 | 	findProjectRoot,
 20 | 	flattenTasksWithSubtasks
 21 | } from '../utils.js';
 22 | import { generateTextService } from '../ai-services-unified.js';
 23 | import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
 24 | import { getPromptManager } from '../prompt-manager.js';
 25 | import generateTaskFiles from './generate-task-files.js';
 26 | import { ContextGatherer } from '../utils/contextGatherer.js';
 27 | import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
 28 | import { tryUpdateViaRemote } from '@tm/bridge';
 29 | 
 30 | /**
 31 |  * Update a subtask by appending additional timestamped information using the unified AI service.
 32 |  * @param {string} tasksPath - Path to the tasks.json file
 33 |  * @param {string} subtaskId - ID of the subtask to update in format "parentId.subtaskId"
 34 |  * @param {string} prompt - Prompt for generating additional information
 35 |  * @param {boolean} [useResearch=false] - Whether to use the research AI role.
 36 |  * @param {Object} context - Context object containing session and mcpLog.
 37 |  * @param {Object} [context.session] - Session object from MCP server.
 38 |  * @param {Object} [context.mcpLog] - MCP logger object.
 39 |  * @param {string} [context.projectRoot] - Project root path (needed for AI service key resolution).
 40 |  * @param {string} [context.tag] - Tag for the task
 41 |  * @param {string} [outputFormat='text'] - Output format ('text' or 'json'). Automatically 'json' if mcpLog is present.
 42 |  * @returns {Promise<Object|null>} - The updated subtask or null if update failed.
 43 |  */
 44 | async function updateSubtaskById(
 45 | 	tasksPath,
 46 | 	subtaskId,
 47 | 	prompt,
 48 | 	useResearch = false,
 49 | 	context = {},
 50 | 	outputFormat = context.mcpLog ? 'json' : 'text'
 51 | ) {
 52 | 	const { session, mcpLog, projectRoot: providedProjectRoot, tag } = context;
 53 | 	const logFn = mcpLog || consoleLog;
 54 | 	const isMCP = !!mcpLog;
 55 | 
 56 | 	// Report helper
 57 | 	const report = (level, ...args) => {
 58 | 		if (isMCP) {
 59 | 			if (typeof logFn[level] === 'function') logFn[level](...args);
 60 | 			else logFn.info(...args);
 61 | 		} else if (!isSilentMode()) {
 62 | 			logFn(level, ...args);
 63 | 		}
 64 | 	};
 65 | 
 66 | 	let loadingIndicator = null;
 67 | 
 68 | 	try {
 69 | 		report('info', `Updating subtask ${subtaskId} with prompt: "${prompt}"`);
 70 | 
 71 | 		if (
 72 | 			!subtaskId ||
 73 | 			typeof subtaskId !== 'string' ||
 74 | 			!subtaskId.includes('.')
 75 | 		) {
 76 | 			throw new Error(
 77 | 				`Invalid subtask ID format: ${subtaskId}. Subtask ID must be in format "parentId.subtaskId"`
 78 | 			);
 79 | 		}
 80 | 
 81 | 		if (!prompt || typeof prompt !== 'string' || prompt.trim() === '') {
 82 | 			throw new Error(
 83 | 				'Prompt cannot be empty. Please provide context for the subtask update.'
 84 | 			);
 85 | 		}
 86 | 
 87 | 		if (!fs.existsSync(tasksPath)) {
 88 | 			throw new Error(`Tasks file not found at path: ${tasksPath}`);
 89 | 		}
 90 | 
 91 | 		const projectRoot = providedProjectRoot || findProjectRoot();
 92 | 		if (!projectRoot) {
 93 | 			throw new Error('Could not determine project root directory');
 94 | 		}
 95 | 
 96 | 		// --- BRIDGE: Try remote update first (API storage) ---
 97 | 		// In API storage, subtask IDs like "1.2" or "TAS-49.1" are just regular task IDs
 98 | 		// So update-subtask and update-task work identically
 99 | 		const remoteResult = await tryUpdateViaRemote({
100 | 			taskId: subtaskId,
101 | 			prompt,
102 | 			projectRoot,
103 | 			tag,
104 | 			appendMode: true, // Subtask updates are always append mode
105 | 			useResearch,
106 | 			isMCP,
107 | 			outputFormat,
108 | 			report
109 | 		});
110 | 
111 | 		// If remote handled it, return the result
112 | 		if (remoteResult) {
113 | 			return {
114 | 				updatedSubtask: { id: subtaskId },
115 | 				telemetryData: remoteResult.telemetryData,
116 | 				tagInfo: remoteResult.tagInfo
117 | 			};
118 | 		}
119 | 		// Otherwise fall through to file-based logic below
120 | 		// --- End BRIDGE ---
121 | 
122 | 		const data = readJSON(tasksPath, projectRoot, tag);
123 | 		if (!data || !data.tasks) {
124 | 			throw new Error(
125 | 				`No valid tasks found in ${tasksPath}. The file may be corrupted or have an invalid format.`
126 | 			);
127 | 		}
128 | 
129 | 		const [parentIdStr, subtaskIdStr] = subtaskId.split('.');
130 | 		const parentId = parseInt(parentIdStr, 10);
131 | 		const subtaskIdNum = parseInt(subtaskIdStr, 10);
132 | 
133 | 		if (
134 | 			Number.isNaN(parentId) ||
135 | 			parentId <= 0 ||
136 | 			Number.isNaN(subtaskIdNum) ||
137 | 			subtaskIdNum <= 0
138 | 		) {
139 | 			throw new Error(
140 | 				`Invalid subtask ID format: ${subtaskId}. Both parent ID and subtask ID must be positive integers.`
141 | 			);
142 | 		}
143 | 
144 | 		const parentTask = data.tasks.find((task) => task.id === parentId);
145 | 		if (!parentTask) {
146 | 			throw new Error(
147 | 				`Parent task with ID ${parentId} not found. Please verify the task ID and try again.`
148 | 			);
149 | 		}
150 | 
151 | 		if (!parentTask.subtasks || !Array.isArray(parentTask.subtasks)) {
152 | 			throw new Error(`Parent task ${parentId} has no subtasks.`);
153 | 		}
154 | 
155 | 		const subtaskIndex = parentTask.subtasks.findIndex(
156 | 			(st) => st.id === subtaskIdNum
157 | 		);
158 | 		if (subtaskIndex === -1) {
159 | 			throw new Error(
160 | 				`Subtask with ID ${subtaskId} not found. Please verify the subtask ID and try again.`
161 | 			);
162 | 		}
163 | 
164 | 		const subtask = parentTask.subtasks[subtaskIndex];
165 | 
166 | 		// --- Context Gathering ---
167 | 		let gatheredContext = '';
168 | 		try {
169 | 			const contextGatherer = new ContextGatherer(projectRoot, tag);
170 | 			const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
171 | 			const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'update-subtask');
172 | 			const searchQuery = `${parentTask.title} ${subtask.title} ${prompt}`;
173 | 			const searchResults = fuzzySearch.findRelevantTasks(searchQuery, {
174 | 				maxResults: 5,
175 | 				includeSelf: true
176 | 			});
177 | 			const relevantTaskIds = fuzzySearch.getTaskIds(searchResults);
178 | 
179 | 			const finalTaskIds = [
180 | 				...new Set([subtaskId.toString(), ...relevantTaskIds])
181 | 			];
182 | 
183 | 			if (finalTaskIds.length > 0) {
184 | 				const contextResult = await contextGatherer.gather({
185 | 					tasks: finalTaskIds,
186 | 					format: 'research'
187 | 				});
188 | 				gatheredContext = contextResult.context || '';
189 | 			}
190 | 		} catch (contextError) {
191 | 			report('warn', `Could not gather context: ${contextError.message}`);
192 | 		}
193 | 		// --- End Context Gathering ---
194 | 
195 | 		if (outputFormat === 'text') {
196 | 			const table = new Table({
197 | 				head: [
198 | 					chalk.cyan.bold('ID'),
199 | 					chalk.cyan.bold('Title'),
200 | 					chalk.cyan.bold('Status')
201 | 				],
202 | 				colWidths: [10, 55, 10]
203 | 			});
204 | 			table.push([
205 | 				subtaskId,
206 | 				truncate(subtask.title, 52),
207 | 				getStatusWithColor(subtask.status)
208 | 			]);
209 | 			console.log(
210 | 				boxen(chalk.white.bold(`Updating Subtask #${subtaskId}`), {
211 | 					padding: 1,
212 | 					borderColor: 'blue',
213 | 					borderStyle: 'round',
214 | 					margin: { top: 1, bottom: 0 }
215 | 				})
216 | 			);
217 | 			console.log(table.toString());
218 | 			loadingIndicator = startLoadingIndicator(
219 | 				useResearch
220 | 					? 'Updating subtask with research...'
221 | 					: 'Updating subtask...'
222 | 			);
223 | 		}
224 | 
225 | 		let generatedContentString = '';
226 | 		let newlyAddedSnippet = '';
227 | 		let aiServiceResponse = null;
228 | 
229 | 		try {
230 | 			const parentContext = {
231 | 				id: parentTask.id,
232 | 				title: parentTask.title
233 | 			};
234 | 			const prevSubtask =
235 | 				subtaskIndex > 0
236 | 					? {
237 | 							id: `${parentTask.id}.${parentTask.subtasks[subtaskIndex - 1].id}`,
238 | 							title: parentTask.subtasks[subtaskIndex - 1].title,
239 | 							status: parentTask.subtasks[subtaskIndex - 1].status
240 | 						}
241 | 					: undefined;
242 | 			const nextSubtask =
243 | 				subtaskIndex < parentTask.subtasks.length - 1
244 | 					? {
245 | 							id: `${parentTask.id}.${parentTask.subtasks[subtaskIndex + 1].id}`,
246 | 							title: parentTask.subtasks[subtaskIndex + 1].title,
247 | 							status: parentTask.subtasks[subtaskIndex + 1].status
248 | 						}
249 | 					: undefined;
250 | 
251 | 			// Build prompts using PromptManager
252 | 			const promptManager = getPromptManager();
253 | 
254 | 			const promptParams = {
255 | 				parentTask: parentContext,
256 | 				prevSubtask: prevSubtask,
257 | 				nextSubtask: nextSubtask,
258 | 				currentDetails: subtask.details || '(No existing details)',
259 | 				updatePrompt: prompt,
260 | 				useResearch: useResearch,
261 | 				gatheredContext: gatheredContext || '',
262 | 				hasCodebaseAnalysis: hasCodebaseAnalysis(
263 | 					useResearch,
264 | 					projectRoot,
265 | 					session
266 | 				),
267 | 				projectRoot: projectRoot
268 | 			};
269 | 
270 | 			const variantKey = useResearch ? 'research' : 'default';
271 | 			const { systemPrompt, userPrompt } = await promptManager.loadPrompt(
272 | 				'update-subtask',
273 | 				promptParams,
274 | 				variantKey
275 | 			);
276 | 
277 | 			const role = useResearch ? 'research' : 'main';
278 | 			report('info', `Using AI text service with role: ${role}`);
279 | 
280 | 			aiServiceResponse = await generateTextService({
281 | 				prompt: userPrompt,
282 | 				systemPrompt: systemPrompt,
283 | 				role,
284 | 				session,
285 | 				projectRoot,
286 | 				maxRetries: 2,
287 | 				commandName: 'update-subtask',
288 | 				outputType: isMCP ? 'mcp' : 'cli'
289 | 			});
290 | 
291 | 			if (
292 | 				aiServiceResponse &&
293 | 				aiServiceResponse.mainResult &&
294 | 				typeof aiServiceResponse.mainResult === 'string'
295 | 			) {
296 | 				generatedContentString = aiServiceResponse.mainResult;
297 | 			} else {
298 | 				generatedContentString = '';
299 | 				report(
300 | 					'warn',
301 | 					'AI service response did not contain expected text string.'
302 | 				);
303 | 			}
304 | 
305 | 			if (outputFormat === 'text' && loadingIndicator) {
306 | 				stopLoadingIndicator(loadingIndicator);
307 | 				loadingIndicator = null;
308 | 			}
309 | 		} catch (aiError) {
310 | 			report('error', `AI service call failed: ${aiError.message}`);
311 | 			if (outputFormat === 'text' && loadingIndicator) {
312 | 				stopLoadingIndicator(loadingIndicator);
313 | 				loadingIndicator = null;
314 | 			}
315 | 			throw aiError;
316 | 		}
317 | 
318 | 		if (generatedContentString && generatedContentString.trim()) {
319 | 			// Check if the string is not empty
320 | 			const timestamp = new Date().toISOString();
321 | 			const formattedBlock = `<info added on ${timestamp}>\n${generatedContentString.trim()}\n</info added on ${timestamp}>`;
322 | 			newlyAddedSnippet = formattedBlock; // <--- ADD THIS LINE: Store for display
323 | 
324 | 			subtask.details =
325 | 				(subtask.details ? subtask.details + '\n' : '') + formattedBlock;
326 | 		} else {
327 | 			report(
328 | 				'warn',
329 | 				'AI response was empty or whitespace after trimming. Original details remain unchanged.'
330 | 			);
331 | 			newlyAddedSnippet = 'No new details were added by the AI.';
332 | 		}
333 | 
334 | 		const updatedSubtask = parentTask.subtasks[subtaskIndex];
335 | 
336 | 		if (outputFormat === 'text' && getDebugFlag(session)) {
337 | 			console.log(
338 | 				'>>> DEBUG: Subtask details AFTER AI update:',
339 | 				updatedSubtask.details
340 | 			);
341 | 		}
342 | 
343 | 		if (updatedSubtask.description) {
344 | 			if (prompt.length < 100) {
345 | 				if (outputFormat === 'text' && getDebugFlag(session)) {
346 | 					console.log(
347 | 						'>>> DEBUG: Subtask description BEFORE append:',
348 | 						updatedSubtask.description
349 | 					);
350 | 				}
351 | 				updatedSubtask.description += ` [Updated: ${new Date().toLocaleDateString()}]`;
352 | 				if (outputFormat === 'text' && getDebugFlag(session)) {
353 | 					console.log(
354 | 						'>>> DEBUG: Subtask description AFTER append:',
355 | 						updatedSubtask.description
356 | 					);
357 | 				}
358 | 			}
359 | 		}
360 | 
361 | 		if (outputFormat === 'text' && getDebugFlag(session)) {
362 | 			console.log('>>> DEBUG: About to call writeJSON with updated data...');
363 | 		}
364 | 		writeJSON(tasksPath, data, projectRoot, tag);
365 | 		if (outputFormat === 'text' && getDebugFlag(session)) {
366 | 			console.log('>>> DEBUG: writeJSON call completed.');
367 | 		}
368 | 
369 | 		report('success', `Successfully updated subtask ${subtaskId}`);
370 | 		// Updated  function call to make sure if uncommented it will generate the task files for the updated subtask based on the tag
371 | 		// await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
372 | 		// 	tag: tag,
373 | 		// 	projectRoot: projectRoot
374 | 		// });
375 | 
376 | 		if (outputFormat === 'text') {
377 | 			if (loadingIndicator) {
378 | 				stopLoadingIndicator(loadingIndicator);
379 | 				loadingIndicator = null;
380 | 			}
381 | 			console.log(
382 | 				boxen(
383 | 					chalk.green(`Successfully updated subtask #${subtaskId}`) +
384 | 						'\n\n' +
385 | 						chalk.white.bold('Title:') +
386 | 						' ' +
387 | 						updatedSubtask.title +
388 | 						'\n\n' +
389 | 						chalk.white.bold('Newly Added Snippet:') +
390 | 						'\n' +
391 | 						chalk.white(newlyAddedSnippet),
392 | 					{ padding: 1, borderColor: 'green', borderStyle: 'round' }
393 | 				)
394 | 			);
395 | 		}
396 | 
397 | 		if (outputFormat === 'text' && aiServiceResponse.telemetryData) {
398 | 			displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli');
399 | 		}
400 | 
401 | 		return {
402 | 			updatedSubtask: updatedSubtask,
403 | 			telemetryData: aiServiceResponse.telemetryData,
404 | 			tagInfo: aiServiceResponse.tagInfo
405 | 		};
406 | 	} catch (error) {
407 | 		if (outputFormat === 'text' && loadingIndicator) {
408 | 			stopLoadingIndicator(loadingIndicator);
409 | 			loadingIndicator = null;
410 | 		}
411 | 		report('error', `Error updating subtask: ${error.message}`);
412 | 		if (outputFormat === 'text') {
413 | 			console.error(chalk.red(`Error: ${error.message}`));
414 | 			if (error.message?.includes('ANTHROPIC_API_KEY')) {
415 | 				console.log(
416 | 					chalk.yellow('\nTo fix this issue, set your Anthropic API key:')
417 | 				);
418 | 				console.log('  export ANTHROPIC_API_KEY=your_api_key_here');
419 | 			} else if (error.message?.includes('PERPLEXITY_API_KEY')) {
420 | 				console.log(chalk.yellow('\nTo fix this issue:'));
421 | 				console.log(
422 | 					'  1. Set your Perplexity API key: export PERPLEXITY_API_KEY=your_api_key_here'
423 | 				);
424 | 				console.log(
425 | 					'  2. Or run without the research flag: task-master update-subtask --id=<id> --prompt="..."'
426 | 				);
427 | 			} else if (error.message?.includes('overloaded')) {
428 | 				console.log(
429 | 					chalk.yellow(
430 | 						'\nAI model overloaded, and fallback failed or was unavailable:'
431 | 					)
432 | 				);
433 | 				console.log('  1. Try again in a few minutes.');
434 | 				console.log('  2. Ensure PERPLEXITY_API_KEY is set for fallback.');
435 | 			} else if (error.message?.includes('not found')) {
436 | 				console.log(chalk.yellow('\nTo fix this issue:'));
437 | 				console.log(
438 | 					'  1. Run task-master list --with-subtasks to see all available subtask IDs'
439 | 				);
440 | 				console.log(
441 | 					'  2. Use a valid subtask ID with the --id parameter in format "parentId.subtaskId"'
442 | 				);
443 | 			} else if (
444 | 				error.message?.includes('empty stream response') ||
445 | 				error.message?.includes('AI did not return a valid text string')
446 | 			) {
447 | 				console.log(
448 | 					chalk.yellow(
449 | 						'\nThe AI model returned an empty or invalid response. This might be due to the prompt or API issues. Try rephrasing or trying again later.'
450 | 					)
451 | 				);
452 | 			}
453 | 			if (getDebugFlag(session)) {
454 | 				console.error(error);
455 | 			}
456 | 		} else {
457 | 			throw error;
458 | 		}
459 | 		return null;
460 | 	}
461 | }
462 | 
463 | export default updateSubtaskById;
464 | 
```

--------------------------------------------------------------------------------
/.taskmaster/docs/tdd-workflow-phase-3-extensibility-guardrails.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Phase 3: Extensibility + Guardrails - Autonomous TDD Workflow
  2 | 
  3 | ## Objective
  4 | Add multi-language/framework support, enhanced safety guardrails, TUI interface, and extensibility for IDE/editor integration.
  5 | 
  6 | ## Scope
  7 | - Multi-language test runner support (pytest, go test, etc.)
  8 | - Enhanced safety: diff preview, confirmation gates, minimal-change prompts
  9 | - Optional TUI panel with tmux integration
 10 | - State-based extension API for IDE integration
 11 | - Parallel subtask execution (experimental)
 12 | 
 13 | ## Deliverables
 14 | 
 15 | ### 1. Multi-Language Test Runner Support
 16 | 
 17 | **Extend TestRunnerAdapter:**
 18 | ```typescript
 19 | class TestRunnerAdapter {
 20 |   // Existing methods...
 21 | 
 22 |   async detectLanguage(): Promise<Language>
 23 |   async detectFramework(language: Language): Promise<Framework>
 24 |   async getFrameworkAdapter(framework: Framework): Promise<FrameworkAdapter>
 25 | }
 26 | 
 27 | enum Language {
 28 |   JavaScript = 'javascript',
 29 |   TypeScript = 'typescript',
 30 |   Python = 'python',
 31 |   Go = 'go',
 32 |   Rust = 'rust'
 33 | }
 34 | 
 35 | enum Framework {
 36 |   Vitest = 'vitest',
 37 |   Jest = 'jest',
 38 |   Pytest = 'pytest',
 39 |   GoTest = 'gotest',
 40 |   CargoTest = 'cargotest'
 41 | }
 42 | 
 43 | interface FrameworkAdapter {
 44 |   runTargeted(pattern: string): Promise<TestResults>
 45 |   runAll(): Promise<TestResults>
 46 |   parseCoverage(output: string): Promise<CoverageReport>
 47 |   getTestFilePattern(): string
 48 |   getTestFileExtension(): string
 49 | }
 50 | ```
 51 | 
 52 | **Framework-specific adapters:**
 53 | 
 54 | **PytestAdapter** (`packages/tm-core/src/services/test-adapters/pytest-adapter.ts`):
 55 | ```typescript
 56 | class PytestAdapter implements FrameworkAdapter {
 57 |   async runTargeted(pattern: string): Promise<TestResults> {
 58 |     const output = await exec(`pytest ${pattern} --json-report`)
 59 |     return this.parseResults(output)
 60 |   }
 61 | 
 62 |   async runAll(): Promise<TestResults> {
 63 |     const output = await exec('pytest --cov --json-report')
 64 |     return this.parseResults(output)
 65 |   }
 66 | 
 67 |   parseCoverage(output: string): Promise<CoverageReport> {
 68 |     // Parse pytest-cov XML output
 69 |   }
 70 | 
 71 |   getTestFilePattern(): string {
 72 |     return '**/test_*.py'
 73 |   }
 74 | 
 75 |   getTestFileExtension(): string {
 76 |     return '.py'
 77 |   }
 78 | }
 79 | ```
 80 | 
 81 | **GoTestAdapter** (`packages/tm-core/src/services/test-adapters/gotest-adapter.ts`):
 82 | ```typescript
 83 | class GoTestAdapter implements FrameworkAdapter {
 84 |   async runTargeted(pattern: string): Promise<TestResults> {
 85 |     const output = await exec(`go test ${pattern} -json`)
 86 |     return this.parseResults(output)
 87 |   }
 88 | 
 89 |   async runAll(): Promise<TestResults> {
 90 |     const output = await exec('go test ./... -coverprofile=coverage.out -json')
 91 |     return this.parseResults(output)
 92 |   }
 93 | 
 94 |   parseCoverage(output: string): Promise<CoverageReport> {
 95 |     // Parse go test coverage output
 96 |   }
 97 | 
 98 |   getTestFilePattern(): string {
 99 |     return '**/*_test.go'
100 |   }
101 | 
102 |   getTestFileExtension(): string {
103 |     return '_test.go'
104 |   }
105 | }
106 | ```
107 | 
108 | **Detection Logic:**
109 | ```typescript
110 | async function detectFramework(): Promise<Framework> {
111 |   // Check for package.json
112 |   if (await exists('package.json')) {
113 |     const pkg = await readJSON('package.json')
114 |     if (pkg.devDependencies?.vitest) return Framework.Vitest
115 |     if (pkg.devDependencies?.jest) return Framework.Jest
116 |   }
117 | 
118 |   // Check for Python files
119 |   if (await exists('pytest.ini') || await exists('setup.py')) {
120 |     return Framework.Pytest
121 |   }
122 | 
123 |   // Check for Go files
124 |   if (await exists('go.mod')) {
125 |     return Framework.GoTest
126 |   }
127 | 
128 |   // Check for Rust files
129 |   if (await exists('Cargo.toml')) {
130 |     return Framework.CargoTest
131 |   }
132 | 
133 |   throw new Error('Could not detect test framework')
134 | }
135 | ```
136 | 
137 | ### 2. Enhanced Safety Guardrails
138 | 
139 | **Diff Preview Mode:**
140 | ```bash
141 | $ tm autopilot 42 --preview-diffs
142 | 
143 | [2/3] Subtask 42.2: Add collection endpoint
144 | 
145 |   RED   ✓ Tests created: src/api/__tests__/metrics.test.js
146 | 
147 |   GREEN Implementing code...
148 | 
149 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
150 | Proposed changes (src/api/metrics.js):
151 | 
152 |   + import { MetricsSchema } from '../models/schema.js'
153 |   +
154 |   + export async function createMetric(data) {
155 |   +   const validated = MetricsSchema.parse(data)
156 |   +   const result = await db.metrics.create(validated)
157 |   +   return result
158 |   + }
159 | 
160 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
161 | 
162 | Apply these changes? [Y/n/e(dit)/s(kip)]
163 |   Y - Apply and continue
164 |   n - Reject and retry GREEN phase
165 |   e - Open in editor for manual changes
166 |   s - Skip this subtask
167 | ```
168 | 
169 | **Minimal Change Enforcement:**
170 | 
171 | Add to system prompt:
172 | ```markdown
173 | CRITICAL: Make MINIMAL changes to pass the failing tests.
174 | - Only modify files directly related to the subtask
175 | - Do not refactor existing code unless absolutely necessary
176 | - Do not add features beyond the acceptance criteria
177 | - Keep changes under 50 lines per file when possible
178 | - Prefer composition over modification
179 | ```
180 | 
181 | **Change Size Warnings:**
182 | ```bash
183 | ⚠️  Large change detected:
184 |   Files modified: 5
185 |   Lines changed: +234, -12
186 | 
187 | This subtask was expected to be small (~50 lines).
188 | Consider:
189 |   - Breaking into smaller subtasks
190 |   - Reviewing acceptance criteria
191 |   - Checking for unintended changes
192 | 
193 | Continue anyway? [y/N]
194 | ```
195 | 
196 | ### 3. TUI Interface with tmux
197 | 
198 | **Layout:**
199 | ```
200 | ┌──────────────────────────────────┬─────────────────────────────────┐
201 | │ Task Navigator (left)            │ Executor Terminal (right)       │
202 | │                                  │                                 │
203 | │ Project: my-app                  │ $ tm autopilot --executor-mode  │
204 | │ Branch: analytics/task-42        │ > Running subtask 42.2 GREEN... │
205 | │ Tag: analytics                   │ > Implementing endpoint...      │
206 | │                                  │ > Tests: 3 passed, 0 failed     │
207 | │ Tasks:                           │ > Ready to commit               │
208 | │ → 42 [in-progress] User metrics  │                                 │
209 | │   → 42.1 [done] Schema           │ [Live output from executor]     │
210 | │   → 42.2 [active] Endpoint ◀     │                                 │
211 | │   → 42.3 [pending] Dashboard     │                                 │
212 | │                                  │                                 │
213 | │ [s] start  [p] pause  [q] quit   │                                 │
214 | └──────────────────────────────────┴─────────────────────────────────┘
215 | ```
216 | 
217 | **Implementation:**
218 | 
219 | **TUI Navigator** (`apps/cli/src/ui/tui/navigator.ts`):
220 | ```typescript
221 | import blessed from 'blessed'
222 | 
223 | class AutopilotTUI {
224 |   private screen: blessed.Widgets.Screen
225 |   private taskList: blessed.Widgets.ListElement
226 |   private statusBox: blessed.Widgets.BoxElement
227 |   private executorPane: string  // tmux pane ID
228 | 
229 |   async start(taskId?: string) {
230 |     // Create blessed screen
231 |     this.screen = blessed.screen()
232 | 
233 |     // Create task list widget
234 |     this.taskList = blessed.list({
235 |       label: 'Tasks',
236 |       keys: true,
237 |       vi: true,
238 |       style: { selected: { bg: 'blue' } }
239 |     })
240 | 
241 |     // Spawn tmux pane for executor
242 |     this.executorPane = await this.spawnExecutorPane()
243 | 
244 |     // Watch state file for updates
245 |     this.watchStateFile()
246 | 
247 |     // Handle keybindings
248 |     this.setupKeybindings()
249 |   }
250 | 
251 |   private async spawnExecutorPane(): Promise<string> {
252 |     const paneId = await exec('tmux split-window -h -P -F "#{pane_id}"')
253 |     await exec(`tmux send-keys -t ${paneId} "tm autopilot --executor-mode" Enter`)
254 |     return paneId.trim()
255 |   }
256 | 
257 |   private watchStateFile() {
258 |     watch('.taskmaster/state/current-run.json', (event, filename) => {
259 |       this.updateDisplay()
260 |     })
261 |   }
262 | 
263 |   private setupKeybindings() {
264 |     this.screen.key(['s'], () => this.startTask())
265 |     this.screen.key(['p'], () => this.pauseTask())
266 |     this.screen.key(['q'], () => this.quit())
267 |     this.screen.key(['up', 'down'], () => this.navigateTasks())
268 |   }
269 | }
270 | ```
271 | 
272 | **Executor Mode:**
273 | ```bash
274 | $ tm autopilot 42 --executor-mode
275 | 
276 | # Runs in executor pane, writes state to shared file
277 | # Left pane reads state file and updates display
278 | ```
279 | 
280 | **State File** (`.taskmaster/state/current-run.json`):
281 | ```json
282 | {
283 |   "runId": "2025-01-15-142033",
284 |   "taskId": "42",
285 |   "status": "running",
286 |   "currentPhase": "green",
287 |   "currentSubtask": "42.2",
288 |   "lastOutput": "Implementing endpoint...",
289 |   "testsStatus": {
290 |     "passed": 3,
291 |     "failed": 0
292 |   }
293 | }
294 | ```
295 | 
296 | ### 4. Extension API for IDE Integration
297 | 
298 | **State-based API:**
299 | 
300 | Expose run state via JSON files that IDEs can read:
301 | - `.taskmaster/state/current-run.json` - live run state
302 | - `.taskmaster/reports/runs/<runId>/manifest.json` - run metadata
303 | - `.taskmaster/reports/runs/<runId>/log.jsonl` - event stream
304 | 
305 | **WebSocket API (optional):**
306 | ```typescript
307 | // packages/tm-core/src/services/autopilot-server.ts
308 | class AutopilotServer {
309 |   private wss: WebSocketServer
310 | 
311 |   start(port: number = 7890) {
312 |     this.wss = new WebSocketServer({ port })
313 | 
314 |     this.wss.on('connection', (ws) => {
315 |       // Send current state
316 |       ws.send(JSON.stringify(this.getCurrentState()))
317 | 
318 |       // Stream events
319 |       this.orchestrator.on('*', (event) => {
320 |         ws.send(JSON.stringify(event))
321 |       })
322 |     })
323 |   }
324 | }
325 | ```
326 | 
327 | **Usage from IDE extension:**
328 | ```typescript
329 | // VS Code extension example
330 | const ws = new WebSocket('ws://localhost:7890')
331 | 
332 | ws.on('message', (data) => {
333 |   const event = JSON.parse(data)
334 | 
335 |   if (event.type === 'subtask:complete') {
336 |     vscode.window.showInformationMessage(
337 |       `Subtask ${event.subtaskId} completed`
338 |     )
339 |   }
340 | })
341 | ```
342 | 
343 | ### 5. Parallel Subtask Execution (Experimental)
344 | 
345 | **Dependency Analysis:**
346 | ```typescript
347 | class SubtaskScheduler {
348 |   async buildDependencyGraph(subtasks: Subtask[]): Promise<DAG> {
349 |     const graph = new DAG()
350 | 
351 |     for (const subtask of subtasks) {
352 |       graph.addNode(subtask.id)
353 | 
354 |       for (const depId of subtask.dependencies) {
355 |         graph.addEdge(depId, subtask.id)
356 |       }
357 |     }
358 | 
359 |     return graph
360 |   }
361 | 
362 |   async getParallelBatches(graph: DAG): Promise<Subtask[][]> {
363 |     const batches: Subtask[][] = []
364 |     const completed = new Set<string>()
365 | 
366 |     while (completed.size < graph.size()) {
367 |       const ready = graph.nodes.filter(node =>
368 |         !completed.has(node.id) &&
369 |         node.dependencies.every(dep => completed.has(dep))
370 |       )
371 | 
372 |       batches.push(ready)
373 |       ready.forEach(node => completed.add(node.id))
374 |     }
375 | 
376 |     return batches
377 |   }
378 | }
379 | ```
380 | 
381 | **Parallel Execution:**
382 | ```bash
383 | $ tm autopilot 42 --parallel
384 | 
385 | [Batch 1] Running 2 subtasks in parallel:
386 |   → 42.1: Add metrics schema
387 |   → 42.4: Add API documentation
388 | 
389 |   42.1 RED   ✓ Tests created
390 |   42.4 RED   ✓ Tests created
391 | 
392 |   42.1 GREEN ✓ Implementation complete
393 |   42.4 GREEN ✓ Implementation complete
394 | 
395 |   42.1 COMMIT ✓ Committed: a1b2c3d
396 |   42.4 COMMIT ✓ Committed: e5f6g7h
397 | 
398 | [Batch 2] Running 2 subtasks in parallel (depend on 42.1):
399 |   → 42.2: Add collection endpoint
400 |   → 42.3: Add dashboard widget
401 |   ...
402 | ```
403 | 
404 | **Conflict Detection:**
405 | ```typescript
406 | async function detectConflicts(subtasks: Subtask[]): Promise<Conflict[]> {
407 |   const conflicts: Conflict[] = []
408 | 
409 |   for (let i = 0; i < subtasks.length; i++) {
410 |     for (let j = i + 1; j < subtasks.length; j++) {
411 |       const filesA = await predictAffectedFiles(subtasks[i])
412 |       const filesB = await predictAffectedFiles(subtasks[j])
413 | 
414 |       const overlap = filesA.filter(f => filesB.includes(f))
415 | 
416 |       if (overlap.length > 0) {
417 |         conflicts.push({
418 |           subtasks: [subtasks[i].id, subtasks[j].id],
419 |           files: overlap
420 |         })
421 |       }
422 |     }
423 |   }
424 | 
425 |   return conflicts
426 | }
427 | ```
428 | 
429 | ### 6. Advanced Configuration
430 | 
431 | **Add to `.taskmaster/config.json`:**
432 | ```json
433 | {
434 |   "autopilot": {
435 |     "safety": {
436 |       "previewDiffs": false,
437 |       "maxChangeLinesPerFile": 100,
438 |       "warnOnLargeChanges": true,
439 |       "requireConfirmOnLargeChanges": true
440 |     },
441 |     "parallel": {
442 |       "enabled": false,
443 |       "maxConcurrent": 3,
444 |       "detectConflicts": true
445 |     },
446 |     "tui": {
447 |       "enabled": false,
448 |       "tmuxSession": "taskmaster-autopilot"
449 |     },
450 |     "api": {
451 |       "enabled": false,
452 |       "port": 7890,
453 |       "allowRemote": false
454 |     }
455 |   },
456 |   "test": {
457 |     "frameworks": {
458 |       "python": {
459 |         "runner": "pytest",
460 |         "coverageCommand": "pytest --cov",
461 |         "testPattern": "**/test_*.py"
462 |       },
463 |       "go": {
464 |         "runner": "go test",
465 |         "coverageCommand": "go test ./... -coverprofile=coverage.out",
466 |         "testPattern": "**/*_test.go"
467 |       }
468 |     }
469 |   }
470 | }
471 | ```
472 | 
473 | ## CLI Updates
474 | 
475 | **New commands:**
476 | ```bash
477 | tm autopilot <taskId> --tui              # Launch TUI interface
478 | tm autopilot <taskId> --parallel         # Enable parallel execution
479 | tm autopilot <taskId> --preview-diffs    # Show diffs before applying
480 | tm autopilot <taskId> --executor-mode    # Run as executor pane
481 | tm autopilot-server start                # Start WebSocket API
482 | ```
483 | 
484 | ## Success Criteria
485 | - Supports Python projects with pytest
486 | - Supports Go projects with go test
487 | - Diff preview prevents unwanted changes
488 | - TUI provides better visibility for long-running tasks
489 | - IDE extensions can integrate via state files or WebSocket
490 | - Parallel execution reduces total time for independent subtasks
491 | 
492 | ## Out of Scope
493 | - Full Electron/web GUI
494 | - AI executor selection UI (defer to Phase 4)
495 | - Multi-repository support
496 | - Remote execution on cloud runners
497 | 
498 | ## Testing Strategy
499 | - Test with Python project (pytest)
500 | - Test with Go project (go test)
501 | - Test diff preview UI with mock changes
502 | - Test parallel execution with independent subtasks
503 | - Test conflict detection with overlapping file changes
504 | - Test TUI with mock tmux environment
505 | 
506 | ## Dependencies
507 | - Phase 2 completed (PR + resumability)
508 | - tmux installed (for TUI)
509 | - blessed or ink library (for TUI rendering)
510 | 
511 | ## Estimated Effort
512 | 3-4 weeks
513 | 
514 | ## Risks & Mitigations
515 | - **Risk:** Parallel execution causes git conflicts
516 |   - **Mitigation:** Conservative conflict detection, sequential fallback
517 | 
518 | - **Risk:** TUI adds complexity and maintenance burden
519 |   - **Mitigation:** Keep TUI optional, state-based design allows alternatives
520 | 
521 | - **Risk:** Framework adapters hard to maintain across versions
522 |   - **Mitigation:** Abstract common parsing logic, document adapter interface
523 | 
524 | - **Risk:** Diff preview slows down workflow
525 |   - **Mitigation:** Make optional, use --preview-diffs flag only when needed
526 | 
527 | ## Validation
528 | Test with:
529 | - Python project with pytest and pytest-cov
530 | - Go project with go test
531 | - Large changes requiring confirmation
532 | - Parallel execution with 3+ independent subtasks
533 | - TUI with task selection and live status updates
534 | - VS Code extension reading state files
535 | 
```

--------------------------------------------------------------------------------
/tests/manual/progress/test-parse-prd.js:
--------------------------------------------------------------------------------

```javascript
  1 | #!/usr/bin/env node
  2 | 
  3 | /**
  4 |  * test-parse-prd.js
  5 |  *
  6 |  * Comprehensive integration test for parse-prd functionality.
  7 |  * Tests MCP streaming, CLI streaming, and non-streaming modes.
  8 |  * Validates token tracking, message formats, and priority indicators across all contexts.
  9 |  */
 10 | 
 11 | import fs from 'fs';
 12 | import path from 'path';
 13 | import chalk from 'chalk';
 14 | import { fileURLToPath } from 'url';
 15 | 
 16 | // Get current directory
 17 | const __filename = fileURLToPath(import.meta.url);
 18 | const __dirname = path.dirname(__filename);
 19 | 
 20 | // Get project root (three levels up from tests/manual/progress/)
 21 | const PROJECT_ROOT = path.resolve(__dirname, '..', '..', '..');
 22 | 
 23 | // Import the parse-prd function
 24 | import parsePRD from '../../../scripts/modules/task-manager/parse-prd/index.js';
 25 | 
 26 | /**
 27 |  * Mock Progress Reporter for testing
 28 |  */
 29 | class MockProgressReporter {
 30 | 	constructor(enableDebug = true) {
 31 | 		this.enableDebug = enableDebug;
 32 | 		this.progressHistory = [];
 33 | 		this.startTime = Date.now();
 34 | 	}
 35 | 
 36 | 	async reportProgress(data) {
 37 | 		const timestamp = Date.now() - this.startTime;
 38 | 
 39 | 		const entry = {
 40 | 			timestamp,
 41 | 			...data
 42 | 		};
 43 | 
 44 | 		this.progressHistory.push(entry);
 45 | 
 46 | 		if (this.enableDebug) {
 47 | 			const percentage = data.total
 48 | 				? Math.round((data.progress / data.total) * 100)
 49 | 				: 0;
 50 | 			console.log(
 51 | 				chalk.blue(`[${timestamp}ms]`),
 52 | 				chalk.green(`${percentage}%`),
 53 | 				chalk.yellow(data.message)
 54 | 			);
 55 | 		}
 56 | 	}
 57 | 
 58 | 	getProgressHistory() {
 59 | 		return this.progressHistory;
 60 | 	}
 61 | 
 62 | 	printSummary() {
 63 | 		console.log(chalk.green('\n=== Progress Summary ==='));
 64 | 		console.log(`Total progress reports: ${this.progressHistory.length}`);
 65 | 		console.log(
 66 | 			`Duration: ${this.progressHistory[this.progressHistory.length - 1]?.timestamp || 0}ms`
 67 | 		);
 68 | 
 69 | 		this.progressHistory.forEach((entry, index) => {
 70 | 			const percentage = entry.total
 71 | 				? Math.round((entry.progress / entry.total) * 100)
 72 | 				: 0;
 73 | 			console.log(
 74 | 				`${index + 1}. [${entry.timestamp}ms] ${percentage}% - ${entry.message}`
 75 | 			);
 76 | 		});
 77 | 
 78 | 		// Check for expected message formats
 79 | 		const hasInitialMessage = this.progressHistory.some(
 80 | 			(entry) =>
 81 | 				entry.message.includes('Starting PRD analysis') &&
 82 | 				entry.message.includes('Input:') &&
 83 | 				entry.message.includes('tokens')
 84 | 		);
 85 | 		// Make regex more flexible to handle potential whitespace variations
 86 | 		const hasTaskMessages = this.progressHistory.some((entry) =>
 87 | 			/^[🔴🟠🟢⚪]{3} Task \d+\/\d+ - .+ \| ~Output: \d+ tokens/u.test(
 88 | 				entry.message.trim()
 89 | 			)
 90 | 		);
 91 | 
 92 | 		const hasCompletionMessage = this.progressHistory.some(
 93 | 			(entry) =>
 94 | 				entry.message.includes('✅ Task Generation Completed') &&
 95 | 				entry.message.includes('Tokens (I/O):')
 96 | 		);
 97 | 
 98 | 		console.log(chalk.cyan('\n=== Message Format Validation ==='));
 99 | 		console.log(
100 | 			`✅ Initial message format: ${hasInitialMessage ? 'PASS' : 'FAIL'}`
101 | 		);
102 | 		console.log(`✅ Task message format: ${hasTaskMessages ? 'PASS' : 'FAIL'}`);
103 | 		console.log(
104 | 			`✅ Completion message format: ${hasCompletionMessage ? 'PASS' : 'FAIL'}`
105 | 		);
106 | 	}
107 | }
108 | 
109 | /**
110 |  * Mock MCP Logger for testing
111 |  */
112 | class MockMCPLogger {
113 | 	constructor(enableDebug = true) {
114 | 		this.enableDebug = enableDebug;
115 | 		this.logs = [];
116 | 	}
117 | 
118 | 	_log(level, ...args) {
119 | 		const entry = {
120 | 			level,
121 | 			timestamp: Date.now(),
122 | 			message: args.join(' ')
123 | 		};
124 | 		this.logs.push(entry);
125 | 
126 | 		if (this.enableDebug) {
127 | 			const color =
128 | 				{
129 | 					info: chalk.blue,
130 | 					warn: chalk.yellow,
131 | 					error: chalk.red,
132 | 					debug: chalk.gray,
133 | 					success: chalk.green
134 | 				}[level] || chalk.white;
135 | 
136 | 			console.log(color(`[${level.toUpperCase()}]`), ...args);
137 | 		}
138 | 	}
139 | 
140 | 	info(...args) {
141 | 		this._log('info', ...args);
142 | 	}
143 | 	warn(...args) {
144 | 		this._log('warn', ...args);
145 | 	}
146 | 	error(...args) {
147 | 		this._log('error', ...args);
148 | 	}
149 | 	debug(...args) {
150 | 		this._log('debug', ...args);
151 | 	}
152 | 	success(...args) {
153 | 		this._log('success', ...args);
154 | 	}
155 | 
156 | 	getLogs() {
157 | 		return this.logs;
158 | 	}
159 | }
160 | 
161 | /**
162 |  * Get the path to the sample PRD file
163 |  */
164 | function getSamplePRDPath() {
165 | 	return path.resolve(PROJECT_ROOT, 'tests', 'fixtures', 'sample-prd.txt');
166 | }
167 | 
168 | /**
169 |  * Create a basic test config file
170 |  */
171 | function createTestConfig() {
172 | 	const testConfig = {
173 | 		models: {
174 | 			main: {
175 | 				provider: 'anthropic',
176 | 				modelId: 'claude-3-5-sonnet',
177 | 				maxTokens: 64000,
178 | 				temperature: 0.2
179 | 			},
180 | 			research: {
181 | 				provider: 'perplexity',
182 | 				modelId: 'sonar-pro',
183 | 				maxTokens: 8700,
184 | 				temperature: 0.1
185 | 			},
186 | 			fallback: {
187 | 				provider: 'anthropic',
188 | 				modelId: 'claude-3-5-sonnet',
189 | 				maxTokens: 64000,
190 | 				temperature: 0.2
191 | 			}
192 | 		},
193 | 		global: {
194 | 			logLevel: 'info',
195 | 			debug: false,
196 | 			defaultSubtasks: 5,
197 | 			defaultPriority: 'medium',
198 | 			projectName: 'Task Master Test',
199 | 			ollamaBaseURL: 'http://localhost:11434/api',
200 | 			bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com'
201 | 		}
202 | 	};
203 | 
204 | 	const taskmasterDir = path.join(__dirname, '.taskmaster');
205 | 	const configPath = path.join(taskmasterDir, 'config.json');
206 | 
207 | 	// Create .taskmaster directory if it doesn't exist
208 | 	if (!fs.existsSync(taskmasterDir)) {
209 | 		fs.mkdirSync(taskmasterDir, { recursive: true });
210 | 	}
211 | 
212 | 	fs.writeFileSync(configPath, JSON.stringify(testConfig, null, 2));
213 | 	return configPath;
214 | }
215 | 
216 | /**
217 |  * Setup test files and configuration
218 |  */
219 | function setupTestFiles(testName) {
220 | 	const testPRDPath = getSamplePRDPath();
221 | 	const testTasksPath = path.join(__dirname, `test-${testName}-tasks.json`);
222 | 	const configPath = createTestConfig();
223 | 
224 | 	// Clean up existing files
225 | 	if (fs.existsSync(testTasksPath)) {
226 | 		fs.unlinkSync(testTasksPath);
227 | 	}
228 | 
229 | 	return { testPRDPath, testTasksPath, configPath };
230 | }
231 | 
232 | /**
233 |  * Clean up test files
234 |  */
235 | function cleanupTestFiles(testTasksPath, configPath) {
236 | 	if (fs.existsSync(testTasksPath)) fs.unlinkSync(testTasksPath);
237 | 	if (fs.existsSync(configPath)) fs.unlinkSync(configPath);
238 | }
239 | 
240 | /**
241 |  * Run parsePRD with configurable options
242 |  */
243 | async function runParsePRD(testPRDPath, testTasksPath, numTasks, options = {}) {
244 | 	const startTime = Date.now();
245 | 
246 | 	const result = await parsePRD(testPRDPath, testTasksPath, numTasks, {
247 | 		force: true,
248 | 		append: false,
249 | 		research: false,
250 | 		projectRoot: PROJECT_ROOT,
251 | 		...options
252 | 	});
253 | 
254 | 	const endTime = Date.now();
255 | 	const duration = endTime - startTime;
256 | 
257 | 	return { result, duration };
258 | }
259 | 
260 | /**
261 |  * Verify task file existence and structure
262 |  */
263 | function verifyTaskResults(testTasksPath) {
264 | 	if (fs.existsSync(testTasksPath)) {
265 | 		const tasksData = JSON.parse(fs.readFileSync(testTasksPath, 'utf8'));
266 | 		console.log(
267 | 			chalk.green(
268 | 				`\n✅ Tasks file created with ${tasksData.tasks.length} tasks`
269 | 			)
270 | 		);
271 | 
272 | 		// Verify task structure
273 | 		const firstTask = tasksData.tasks[0];
274 | 		if (firstTask && firstTask.id && firstTask.title && firstTask.description) {
275 | 			console.log(chalk.green('✅ Task structure is valid'));
276 | 			return true;
277 | 		} else {
278 | 			console.log(chalk.red('❌ Task structure is invalid'));
279 | 			return false;
280 | 		}
281 | 	} else {
282 | 		console.log(chalk.red('❌ Tasks file was not created'));
283 | 		return false;
284 | 	}
285 | }
286 | 
287 | /**
288 |  * Print MCP-specific logs and validation
289 |  */
290 | function printMCPResults(mcpLogger, progressReporter) {
291 | 	// Print progress summary
292 | 	progressReporter.printSummary();
293 | 
294 | 	// Print MCP logs
295 | 	console.log(chalk.cyan('\n=== MCP Logs ==='));
296 | 	const logs = mcpLogger.getLogs();
297 | 	logs.forEach((log, index) => {
298 | 		const color =
299 | 			{
300 | 				info: chalk.blue,
301 | 				warn: chalk.yellow,
302 | 				error: chalk.red,
303 | 				debug: chalk.gray,
304 | 				success: chalk.green
305 | 			}[log.level] || chalk.white;
306 | 		console.log(
307 | 			`${index + 1}. ${color(`[${log.level.toUpperCase()}]`)} ${log.message}`
308 | 		);
309 | 	});
310 | 
311 | 	// Verify MCP-specific message formats (should use emoji indicators)
312 | 	const hasEmojiIndicators = progressReporter
313 | 		.getProgressHistory()
314 | 		.some((entry) => /[🔴🟠🟢]/u.test(entry.message));
315 | 
316 | 	console.log(chalk.cyan('\n=== MCP-Specific Validation ==='));
317 | 	console.log(
318 | 		`✅ Emoji priority indicators: ${hasEmojiIndicators ? 'PASS' : 'FAIL'}`
319 | 	);
320 | 
321 | 	return { hasEmojiIndicators, logs };
322 | }
323 | 
324 | /**
325 |  * Test MCP streaming with proper MCP context
326 |  */
327 | async function testMCPStreaming(numTasks = 10) {
328 | 	console.log(chalk.cyan('🧪 Testing MCP Streaming Functionality\n'));
329 | 
330 | 	const { testPRDPath, testTasksPath, configPath } = setupTestFiles('mcp');
331 | 	const progressReporter = new MockProgressReporter(true);
332 | 	const mcpLogger = new MockMCPLogger(true); // Enable debug for MCP context
333 | 
334 | 	try {
335 | 		console.log(chalk.yellow('Starting MCP streaming test...'));
336 | 
337 | 		const { result, duration } = await runParsePRD(
338 | 			testPRDPath,
339 | 			testTasksPath,
340 | 			numTasks,
341 | 			{
342 | 				reportProgress: progressReporter.reportProgress.bind(progressReporter),
343 | 				mcpLog: mcpLogger // Add MCP context - this is the key difference
344 | 			}
345 | 		);
346 | 
347 | 		console.log(
348 | 			chalk.green(`\n✅ MCP streaming test completed in ${duration}ms`)
349 | 		);
350 | 
351 | 		const { hasEmojiIndicators, logs } = printMCPResults(
352 | 			mcpLogger,
353 | 			progressReporter
354 | 		);
355 | 		const isValidStructure = verifyTaskResults(testTasksPath);
356 | 
357 | 		return {
358 | 			success: true,
359 | 			duration,
360 | 			progressHistory: progressReporter.getProgressHistory(),
361 | 			mcpLogs: logs,
362 | 			hasEmojiIndicators,
363 | 			result
364 | 		};
365 | 	} catch (error) {
366 | 		console.error(chalk.red(`❌ MCP streaming test failed: ${error.message}`));
367 | 		return {
368 | 			success: false,
369 | 			error: error.message
370 | 		};
371 | 	} finally {
372 | 		cleanupTestFiles(testTasksPath, configPath);
373 | 	}
374 | }
375 | 
376 | /**
377 |  * Test CLI streaming (no reportProgress)
378 |  */
379 | async function testCLIStreaming(numTasks = 10) {
380 | 	console.log(chalk.cyan('🧪 Testing CLI Streaming (No Progress Reporter)\n'));
381 | 
382 | 	const { testPRDPath, testTasksPath, configPath } = setupTestFiles('cli');
383 | 
384 | 	try {
385 | 		console.log(chalk.yellow('Starting CLI streaming test...'));
386 | 
387 | 		// No reportProgress provided; CLI text mode uses the default streaming reporter
388 | 		const { result, duration } = await runParsePRD(
389 | 			testPRDPath,
390 | 			testTasksPath,
391 | 			numTasks
392 | 		);
393 | 
394 | 		console.log(
395 | 			chalk.green(`\n✅ CLI streaming test completed in ${duration}ms`)
396 | 		);
397 | 
398 | 		const isValidStructure = verifyTaskResults(testTasksPath);
399 | 
400 | 		return {
401 | 			success: true,
402 | 			duration,
403 | 			result
404 | 		};
405 | 	} catch (error) {
406 | 		console.error(chalk.red(`❌ CLI streaming test failed: ${error.message}`));
407 | 		return {
408 | 			success: false,
409 | 			error: error.message
410 | 		};
411 | 	} finally {
412 | 		cleanupTestFiles(testTasksPath, configPath);
413 | 	}
414 | }
415 | 
416 | /**
417 |  * Test non-streaming functionality
418 |  */
419 | async function testNonStreaming(numTasks = 10) {
420 | 	console.log(chalk.cyan('🧪 Testing Non-Streaming Functionality\n'));
421 | 
422 | 	const { testPRDPath, testTasksPath, configPath } =
423 | 		setupTestFiles('non-streaming');
424 | 
425 | 	try {
426 | 		console.log(chalk.yellow('Starting non-streaming test...'));
427 | 
428 | 		// Force non-streaming by not providing reportProgress
429 | 		const { result, duration } = await runParsePRD(
430 | 			testPRDPath,
431 | 			testTasksPath,
432 | 			numTasks
433 | 		);
434 | 
435 | 		console.log(
436 | 			chalk.green(`\n✅ Non-streaming test completed in ${duration}ms`)
437 | 		);
438 | 
439 | 		const isValidStructure = verifyTaskResults(testTasksPath);
440 | 
441 | 		return {
442 | 			success: true,
443 | 			duration,
444 | 			result
445 | 		};
446 | 	} catch (error) {
447 | 		console.error(chalk.red(`❌ Non-streaming test failed: ${error.message}`));
448 | 		return {
449 | 			success: false,
450 | 			error: error.message
451 | 		};
452 | 	} finally {
453 | 		cleanupTestFiles(testTasksPath, configPath);
454 | 	}
455 | }
456 | 
457 | /**
458 |  * Compare results between streaming and non-streaming
459 |  */
460 | function compareResults(streamingResult, nonStreamingResult) {
461 | 	console.log(chalk.cyan('\n=== Results Comparison ==='));
462 | 
463 | 	if (!streamingResult.success || !nonStreamingResult.success) {
464 | 		console.log(chalk.red('❌ Cannot compare - one or both tests failed'));
465 | 		return;
466 | 	}
467 | 
468 | 	console.log(`Streaming duration: ${streamingResult.duration}ms`);
469 | 	console.log(`Non-streaming duration: ${nonStreamingResult.duration}ms`);
470 | 
471 | 	const durationDiff = Math.abs(
472 | 		streamingResult.duration - nonStreamingResult.duration
473 | 	);
474 | 	const durationDiffPercent = Math.round(
475 | 		(durationDiff /
476 | 			Math.max(streamingResult.duration, nonStreamingResult.duration)) *
477 | 			100
478 | 	);
479 | 
480 | 	console.log(
481 | 		`Duration difference: ${durationDiff}ms (${durationDiffPercent}%)`
482 | 	);
483 | 
484 | 	if (streamingResult.progressHistory) {
485 | 		console.log(
486 | 			`Streaming progress reports: ${streamingResult.progressHistory.length}`
487 | 		);
488 | 	}
489 | 
490 | 	console.log(chalk.green('✅ Both methods completed successfully'));
491 | }
492 | 
493 | /**
494 |  * Main test runner
495 |  */
496 | async function main() {
497 | 	const args = process.argv.slice(2);
498 | 	const testType = args[0] || 'streaming';
499 | 	const numTasks = parseInt(args[1]) || 8;
500 | 
501 | 	console.log(chalk.bold.cyan('🚀 Task Master PRD Streaming Tests\n'));
502 | 	console.log(chalk.blue(`Test type: ${testType}`));
503 | 	console.log(chalk.blue(`Number of tasks: ${numTasks}\n`));
504 | 
505 | 	try {
506 | 		switch (testType.toLowerCase()) {
507 | 			case 'mcp':
508 | 			case 'mcp-streaming':
509 | 				await testMCPStreaming(numTasks);
510 | 				break;
511 | 
512 | 			case 'cli':
513 | 			case 'cli-streaming':
514 | 				await testCLIStreaming(numTasks);
515 | 				break;
516 | 
517 | 			case 'non-streaming':
518 | 			case 'non':
519 | 				await testNonStreaming(numTasks);
520 | 				break;
521 | 
522 | 			case 'both': {
523 | 				console.log(
524 | 					chalk.yellow(
525 | 						'Running both MCP streaming and non-streaming tests...\n'
526 | 					)
527 | 				);
528 | 				const mcpStreamingResult = await testMCPStreaming(numTasks);
529 | 				console.log('\n' + '='.repeat(60) + '\n');
530 | 				const nonStreamingResult = await testNonStreaming(numTasks);
531 | 				compareResults(mcpStreamingResult, nonStreamingResult);
532 | 				break;
533 | 			}
534 | 
535 | 			case 'all': {
536 | 				console.log(chalk.yellow('Running all test types...\n'));
537 | 				const mcpResult = await testMCPStreaming(numTasks);
538 | 				console.log('\n' + '='.repeat(60) + '\n');
539 | 				const cliResult = await testCLIStreaming(numTasks);
540 | 				console.log('\n' + '='.repeat(60) + '\n');
541 | 				const nonStreamResult = await testNonStreaming(numTasks);
542 | 
543 | 				console.log(chalk.cyan('\n=== All Tests Summary ==='));
544 | 				console.log(
545 | 					`MCP Streaming: ${mcpResult.success ? '✅ PASS' : '❌ FAIL'} ${mcpResult.hasEmojiIndicators ? '(✅ Emojis)' : '(❌ No Emojis)'}`
546 | 				);
547 | 				console.log(
548 | 					`CLI Streaming: ${cliResult.success ? '✅ PASS' : '❌ FAIL'}`
549 | 				);
550 | 				console.log(
551 | 					`Non-streaming: ${nonStreamResult.success ? '✅ PASS' : '❌ FAIL'}`
552 | 				);
553 | 				break;
554 | 			}
555 | 
556 | 			default:
557 | 				console.log(chalk.red(`Unknown test type: ${testType}`));
558 | 				console.log(
559 | 					chalk.yellow(
560 | 						'Available options: mcp-streaming, cli-streaming, non-streaming, both, all'
561 | 					)
562 | 				);
563 | 				process.exit(1);
564 | 		}
565 | 
566 | 		console.log(chalk.green('\n🎉 Tests completed successfully!'));
567 | 	} catch (error) {
568 | 		console.error(chalk.red(`\n❌ Test failed: ${error.message}`));
569 | 		console.error(chalk.red(error.stack));
570 | 		process.exit(1);
571 | 	}
572 | }
573 | 
574 | // Run if called directly
575 | if (import.meta.url === `file://${process.argv[1]}`) {
576 | 	main();
577 | }
578 | 
```

--------------------------------------------------------------------------------
/.taskmaster/templates/example_prd_rpg.md:
--------------------------------------------------------------------------------

```markdown
  1 | <rpg-method>
  2 | # Repository Planning Graph (RPG) Method - PRD Template
  3 | 
  4 | This template teaches you (AI or human) how to create structured, dependency-aware PRDs using the RPG methodology from Microsoft Research. The key insight: separate WHAT (functional) from HOW (structural), then connect them with explicit dependencies.
  5 | 
  6 | ## Core Principles
  7 | 
  8 | 1. **Dual-Semantics**: Think functional (capabilities) AND structural (code organization) separately, then map them
  9 | 2. **Explicit Dependencies**: Never assume - always state what depends on what
 10 | 3. **Topological Order**: Build foundation first, then layers on top
 11 | 4. **Progressive Refinement**: Start broad, refine iteratively
 12 | 
 13 | ## How to Use This Template
 14 | 
 15 | - Follow the instructions in each `<instruction>` block
 16 | - Look at `<example>` blocks to see good vs bad patterns
 17 | - Fill in the content sections with your project details
 18 | - The AI reading this will learn the RPG method by following along
 19 | - Task Master will parse the resulting PRD into dependency-aware tasks
 20 | 
 21 | ## Recommended Tools for Creating PRDs
 22 | 
 23 | When using this template to **create** a PRD (not parse it), use **code-context-aware AI assistants** for best results:
 24 | 
 25 | **Why?** The AI needs to understand your existing codebase to make good architectural decisions about modules, dependencies, and integration points.
 26 | 
 27 | **Recommended tools:**
 28 | - **Claude Code** (claude-code CLI) - Best for structured reasoning and large contexts
 29 | - **Cursor/Windsurf** - IDE integration with full codebase context
 30 | - **Gemini CLI** (gemini-cli) - Massive context window for large codebases
 31 | - **Codex/Grok CLI** - Strong code generation with context awareness
 32 | 
 33 | **Note:** Once your PRD is created, `task-master parse-prd` works with any configured AI model - it just needs to read the PRD text itself, not your codebase.
 34 | </rpg-method>
 35 | 
 36 | ---
 37 | 
 38 | <overview>
 39 | <instruction>
 40 | Start with the problem, not the solution. Be specific about:
 41 | - What pain point exists?
 42 | - Who experiences it?
 43 | - Why existing solutions don't work?
 44 | - What success looks like (measurable outcomes)?
 45 | 
 46 | Keep this section focused - don't jump into implementation details yet.
 47 | </instruction>
 48 | 
 49 | ## Problem Statement
 50 | [Describe the core problem. Be concrete about user pain points.]
 51 | 
 52 | ## Target Users
 53 | [Define personas, their workflows, and what they're trying to achieve.]
 54 | 
 55 | ## Success Metrics
 56 | [Quantifiable outcomes. Examples: "80% task completion via autopilot", "< 5% manual intervention rate"]
 57 | 
 58 | </overview>
 59 | 
 60 | ---
 61 | 
 62 | <functional-decomposition>
 63 | <instruction>
 64 | Now think about CAPABILITIES (what the system DOES), not code structure yet.
 65 | 
 66 | Step 1: Identify high-level capability domains
 67 | - Think: "What major things does this system do?"
 68 | - Examples: Data Management, Core Processing, Presentation Layer
 69 | 
 70 | Step 2: For each capability, enumerate specific features
 71 | - Use explore-exploit strategy:
 72 |   * Exploit: What features are REQUIRED for core value?
 73 |   * Explore: What features make this domain COMPLETE?
 74 | 
 75 | Step 3: For each feature, define:
 76 | - Description: What it does in one sentence
 77 | - Inputs: What data/context it needs
 78 | - Outputs: What it produces/returns
 79 | - Behavior: Key logic or transformations
 80 | 
 81 | <example type="good">
 82 | Capability: Data Validation
 83 |   Feature: Schema validation
 84 |     - Description: Validate JSON payloads against defined schemas
 85 |     - Inputs: JSON object, schema definition
 86 |     - Outputs: Validation result (pass/fail) + error details
 87 |     - Behavior: Iterate fields, check types, enforce constraints
 88 | 
 89 |   Feature: Business rule validation
 90 |     - Description: Apply domain-specific validation rules
 91 |     - Inputs: Validated data object, rule set
 92 |     - Outputs: Boolean + list of violated rules
 93 |     - Behavior: Execute rules sequentially, short-circuit on failure
 94 | </example>
 95 | 
 96 | <example type="bad">
 97 | Capability: validation.js
 98 |   (Problem: This is a FILE, not a CAPABILITY. Mixing structure into functional thinking.)
 99 | 
100 | Capability: Validation
101 |   Feature: Make sure data is good
102 |   (Problem: Too vague. No inputs/outputs. Not actionable.)
103 | </example>
104 | </instruction>
105 | 
106 | ## Capability Tree
107 | 
108 | ### Capability: [Name]
109 | [Brief description of what this capability domain covers]
110 | 
111 | #### Feature: [Name]
112 | - **Description**: [One sentence]
113 | - **Inputs**: [What it needs]
114 | - **Outputs**: [What it produces]
115 | - **Behavior**: [Key logic]
116 | 
117 | #### Feature: [Name]
118 | - **Description**:
119 | - **Inputs**:
120 | - **Outputs**:
121 | - **Behavior**:
122 | 
123 | ### Capability: [Name]
124 | ...
125 | 
126 | </functional-decomposition>
127 | 
128 | ---
129 | 
130 | <structural-decomposition>
131 | <instruction>
132 | NOW think about code organization. Map capabilities to actual file/folder structure.
133 | 
134 | Rules:
135 | 1. Each capability maps to a module (folder or file)
136 | 2. Features within a capability map to functions/classes
137 | 3. Use clear module boundaries - each module has ONE responsibility
138 | 4. Define what each module exports (public interface)
139 | 
140 | The goal: Create a clear mapping between "what it does" (functional) and "where it lives" (structural).
141 | 
142 | <example type="good">
143 | Capability: Data Validation
144 |   → Maps to: src/validation/
145 |     ├── schema-validator.js      (Schema validation feature)
146 |     ├── rule-validator.js         (Business rule validation feature)
147 |     └── index.js                  (Public exports)
148 | 
149 | Exports:
150 |   - validateSchema(data, schema)
151 |   - validateRules(data, rules)
152 | </example>
153 | 
154 | <example type="bad">
155 | Capability: Data Validation
156 |   → Maps to: src/utils.js
157 |   (Problem: "utils" is not a clear module boundary. Where do I find validation logic?)
158 | 
159 | Capability: Data Validation
160 |   → Maps to: src/validation/everything.js
161 |   (Problem: One giant file. Features should map to separate files for maintainability.)
162 | </example>
163 | </instruction>
164 | 
165 | ## Repository Structure
166 | 
167 | ```
168 | project-root/
169 | ├── src/
170 | │   ├── [module-name]/       # Maps to: [Capability Name]
171 | │   │   ├── [file].js        # Maps to: [Feature Name]
172 | │   │   └── index.js         # Public exports
173 | │   └── [module-name]/
174 | ├── tests/
175 | └── docs/
176 | ```
177 | 
178 | ## Module Definitions
179 | 
180 | ### Module: [Name]
181 | - **Maps to capability**: [Capability from functional decomposition]
182 | - **Responsibility**: [Single clear purpose]
183 | - **File structure**:
184 |   ```
185 |   module-name/
186 |   ├── feature1.js
187 |   ├── feature2.js
188 |   └── index.js
189 |   ```
190 | - **Exports**:
191 |   - `functionName()` - [what it does]
192 |   - `ClassName` - [what it does]
193 | 
194 | </structural-decomposition>
195 | 
196 | ---
197 | 
198 | <dependency-graph>
199 | <instruction>
200 | This is THE CRITICAL SECTION for Task Master parsing.
201 | 
202 | Define explicit dependencies between modules. This creates the topological order for task execution.
203 | 
204 | Rules:
205 | 1. List modules in dependency order (foundation first)
206 | 2. For each module, state what it depends on
207 | 3. Foundation modules should have NO dependencies
208 | 4. Every non-foundation module should depend on at least one other module
209 | 5. Think: "What must EXIST before I can build this module?"
210 | 
211 | <example type="good">
212 | Foundation Layer (no dependencies):
213 |   - error-handling: No dependencies
214 |   - config-manager: No dependencies
215 |   - base-types: No dependencies
216 | 
217 | Data Layer:
218 |   - schema-validator: Depends on [base-types, error-handling]
219 |   - data-ingestion: Depends on [schema-validator, config-manager]
220 | 
221 | Core Layer:
222 |   - algorithm-engine: Depends on [base-types, error-handling]
223 |   - pipeline-orchestrator: Depends on [algorithm-engine, data-ingestion]
224 | </example>
225 | 
226 | <example type="bad">
227 | - validation: Depends on API
228 | - API: Depends on validation
229 | (Problem: Circular dependency. This will cause build/runtime issues.)
230 | 
231 | - user-auth: Depends on everything
232 | (Problem: Too many dependencies. Should be more focused.)
233 | </example>
234 | </instruction>
235 | 
236 | ## Dependency Chain
237 | 
238 | ### Foundation Layer (Phase 0)
239 | No dependencies - these are built first.
240 | 
241 | - **[Module Name]**: [What it provides]
242 | - **[Module Name]**: [What it provides]
243 | 
244 | ### [Layer Name] (Phase 1)
245 | - **[Module Name]**: Depends on [[module-from-phase-0], [module-from-phase-0]]
246 | - **[Module Name]**: Depends on [[module-from-phase-0]]
247 | 
248 | ### [Layer Name] (Phase 2)
249 | - **[Module Name]**: Depends on [[module-from-phase-1], [module-from-foundation]]
250 | 
251 | [Continue building up layers...]
252 | 
253 | </dependency-graph>
254 | 
255 | ---
256 | 
257 | <implementation-roadmap>
258 | <instruction>
259 | Turn the dependency graph into concrete development phases.
260 | 
261 | Each phase should:
262 | 1. Have clear entry criteria (what must exist before starting)
263 | 2. Contain tasks that can be parallelized (no inter-dependencies within phase)
264 | 3. Have clear exit criteria (how do we know phase is complete?)
265 | 4. Build toward something USABLE (not just infrastructure)
266 | 
267 | Phase ordering follows topological sort of dependency graph.
268 | 
269 | <example type="good">
270 | Phase 0: Foundation
271 |   Entry: Clean repository
272 |   Tasks:
273 |     - Implement error handling utilities
274 |     - Create base type definitions
275 |     - Setup configuration system
276 |   Exit: Other modules can import foundation without errors
277 | 
278 | Phase 1: Data Layer
279 |   Entry: Phase 0 complete
280 |   Tasks:
281 |     - Implement schema validator (uses: base types, error handling)
282 |     - Build data ingestion pipeline (uses: validator, config)
283 |   Exit: End-to-end data flow from input to validated output
284 | </example>
285 | 
286 | <example type="bad">
287 | Phase 1: Build Everything
288 |   Tasks:
289 |     - API
290 |     - Database
291 |     - UI
292 |     - Tests
293 |   (Problem: No clear focus. Too broad. Dependencies not considered.)
294 | </example>
295 | </instruction>
296 | 
297 | ## Development Phases
298 | 
299 | ### Phase 0: [Foundation Name]
300 | **Goal**: [What foundational capability this establishes]
301 | 
302 | **Entry Criteria**: [What must be true before starting]
303 | 
304 | **Tasks**:
305 | - [ ] [Task name] (depends on: [none or list])
306 |   - Acceptance criteria: [How we know it's done]
307 |   - Test strategy: [What tests prove it works]
308 | 
309 | - [ ] [Task name] (depends on: [none or list])
310 | 
311 | **Exit Criteria**: [Observable outcome that proves phase complete]
312 | 
313 | **Delivers**: [What can users/developers do after this phase?]
314 | 
315 | ---
316 | 
317 | ### Phase 1: [Layer Name]
318 | **Goal**:
319 | 
320 | **Entry Criteria**: Phase 0 complete
321 | 
322 | **Tasks**:
323 | - [ ] [Task name] (depends on: [[tasks-from-phase-0]])
324 | - [ ] [Task name] (depends on: [[tasks-from-phase-0]])
325 | 
326 | **Exit Criteria**:
327 | 
328 | **Delivers**:
329 | 
330 | ---
331 | 
332 | [Continue with more phases...]
333 | 
334 | </implementation-roadmap>
335 | 
336 | ---
337 | 
338 | <test-strategy>
339 | <instruction>
340 | Define how testing will be integrated throughout development (TDD approach).
341 | 
342 | Specify:
343 | 1. Test pyramid ratios (unit vs integration vs e2e)
344 | 2. Coverage requirements
345 | 3. Critical test scenarios
346 | 4. Test generation guidelines for Surgical Test Generator
347 | 
348 | This section guides the AI when generating tests during the RED phase of TDD.
349 | 
350 | <example type="good">
351 | Critical Test Scenarios for Data Validation module:
352 |   - Happy path: Valid data passes all checks
353 |   - Edge cases: Empty strings, null values, boundary numbers
354 |   - Error cases: Invalid types, missing required fields
355 |   - Integration: Validator works with ingestion pipeline
356 | </example>
357 | </instruction>
358 | 
359 | ## Test Pyramid
360 | 
361 | ```
362 |         /\
363 |        /E2E\       ← [X]% (End-to-end, slow, comprehensive)
364 |       /------\
365 |      /Integration\ ← [Y]% (Module interactions)
366 |     /------------\
367 |    /  Unit Tests  \ ← [Z]% (Fast, isolated, deterministic)
368 |   /----------------\
369 | ```
370 | 
371 | ## Coverage Requirements
372 | - Line coverage: [X]% minimum
373 | - Branch coverage: [X]% minimum
374 | - Function coverage: [X]% minimum
375 | - Statement coverage: [X]% minimum
376 | 
377 | ## Critical Test Scenarios
378 | 
379 | ### [Module/Feature Name]
380 | **Happy path**:
381 | - [Scenario description]
382 | - Expected: [What should happen]
383 | 
384 | **Edge cases**:
385 | - [Scenario description]
386 | - Expected: [What should happen]
387 | 
388 | **Error cases**:
389 | - [Scenario description]
390 | - Expected: [How system handles failure]
391 | 
392 | **Integration points**:
393 | - [What interactions to test]
394 | - Expected: [End-to-end behavior]
395 | 
396 | ## Test Generation Guidelines
397 | [Specific instructions for Surgical Test Generator about what to focus on, what patterns to follow, project-specific test conventions]
398 | 
399 | </test-strategy>
400 | 
401 | ---
402 | 
403 | <architecture>
404 | <instruction>
405 | Describe technical architecture, data models, and key design decisions.
406 | 
407 | Keep this section AFTER functional/structural decomposition - implementation details come after understanding structure.
408 | </instruction>
409 | 
410 | ## System Components
411 | [Major architectural pieces and their responsibilities]
412 | 
413 | ## Data Models
414 | [Core data structures, schemas, database design]
415 | 
416 | ## Technology Stack
417 | [Languages, frameworks, key libraries]
418 | 
419 | **Decision: [Technology/Pattern]**
420 | - **Rationale**: [Why chosen]
421 | - **Trade-offs**: [What we're giving up]
422 | - **Alternatives considered**: [What else we looked at]
423 | 
424 | </architecture>
425 | 
426 | ---
427 | 
428 | <risks>
429 | <instruction>
430 | Identify risks that could derail development and how to mitigate them.
431 | 
432 | Categories:
433 | - Technical risks (complexity, unknowns)
434 | - Dependency risks (blocking issues)
435 | - Scope risks (creep, underestimation)
436 | </instruction>
437 | 
438 | ## Technical Risks
439 | **Risk**: [Description]
440 | - **Impact**: [High/Medium/Low - effect on project]
441 | - **Likelihood**: [High/Medium/Low]
442 | - **Mitigation**: [How to address]
443 | - **Fallback**: [Plan B if mitigation fails]
444 | 
445 | ## Dependency Risks
446 | [External dependencies, blocking issues]
447 | 
448 | ## Scope Risks
449 | [Scope creep, underestimation, unclear requirements]
450 | 
451 | </risks>
452 | 
453 | ---
454 | 
455 | <appendix>
456 | ## References
457 | [Papers, documentation, similar systems]
458 | 
459 | ## Glossary
460 | [Domain-specific terms]
461 | 
462 | ## Open Questions
463 | [Things to resolve during development]
464 | </appendix>
465 | 
466 | ---
467 | 
468 | <task-master-integration>
469 | # How Task Master Uses This PRD
470 | 
471 | When you run `task-master parse-prd <file>.txt`, the parser:
472 | 
473 | 1. **Extracts capabilities** → Main tasks
474 |    - Each `### Capability:` becomes a top-level task
475 | 
476 | 2. **Extracts features** → Subtasks
477 |    - Each `#### Feature:` becomes a subtask under its capability
478 | 
479 | 3. **Parses dependencies** → Task dependencies
480 |    - `Depends on: [X, Y]` sets task.dependencies = ["X", "Y"]
481 | 
482 | 4. **Orders by phases** → Task priorities
483 |    - Phase 0 tasks = highest priority
484 |    - Phase N tasks = lower priority, properly sequenced
485 | 
486 | 5. **Uses test strategy** → Test generation context
487 |    - Feeds test scenarios to Surgical Test Generator during implementation
488 | 
489 | **Result**: A dependency-aware task graph that can be executed in topological order.
490 | 
491 | ## Why RPG Structure Matters
492 | 
493 | Traditional flat PRDs lead to:
494 | - ❌ Unclear task dependencies
495 | - ❌ Arbitrary task ordering
496 | - ❌ Circular dependencies discovered late
497 | - ❌ Poorly scoped tasks
498 | 
499 | RPG-structured PRDs provide:
500 | - ✅ Explicit dependency chains
501 | - ✅ Topological execution order
502 | - ✅ Clear module boundaries
503 | - ✅ Validated task graph before implementation
504 | 
505 | ## Tips for Best Results
506 | 
507 | 1. **Spend time on dependency graph** - This is the most valuable section for Task Master
508 | 2. **Keep features atomic** - Each feature should be independently testable
509 | 3. **Progressive refinement** - Start broad, use `task-master expand` to break down complex tasks
510 | 4. **Use research mode** - `task-master parse-prd --research` leverages AI for better task generation
511 | </task-master-integration>
512 | 
```

--------------------------------------------------------------------------------
/assets/example_prd_rpg.txt:
--------------------------------------------------------------------------------

```
  1 | <rpg-method>
  2 | # Repository Planning Graph (RPG) Method - PRD Template
  3 | 
  4 | This template teaches you (AI or human) how to create structured, dependency-aware PRDs using the RPG methodology from Microsoft Research. The key insight: separate WHAT (functional) from HOW (structural), then connect them with explicit dependencies.
  5 | 
  6 | ## Core Principles
  7 | 
  8 | 1. **Dual-Semantics**: Think functional (capabilities) AND structural (code organization) separately, then map them
  9 | 2. **Explicit Dependencies**: Never assume - always state what depends on what
 10 | 3. **Topological Order**: Build foundation first, then layers on top
 11 | 4. **Progressive Refinement**: Start broad, refine iteratively
 12 | 
 13 | ## How to Use This Template
 14 | 
 15 | - Follow the instructions in each `<instruction>` block
 16 | - Look at `<example>` blocks to see good vs bad patterns
 17 | - Fill in the content sections with your project details
 18 | - The AI reading this will learn the RPG method by following along
 19 | - Task Master will parse the resulting PRD into dependency-aware tasks
 20 | 
 21 | ## Recommended Tools for Creating PRDs
 22 | 
 23 | When using this template to **create** a PRD (not parse it), use **code-context-aware AI assistants** for best results:
 24 | 
 25 | **Why?** The AI needs to understand your existing codebase to make good architectural decisions about modules, dependencies, and integration points.
 26 | 
 27 | **Recommended tools:**
 28 | - **Claude Code** (claude-code CLI) - Best for structured reasoning and large contexts
 29 | - **Cursor/Windsurf** - IDE integration with full codebase context
 30 | - **Gemini CLI** (gemini-cli) - Massive context window for large codebases
 31 | - **Codex/Grok CLI** - Strong code generation with context awareness
 32 | 
 33 | **Note:** Once your PRD is created, `task-master parse-prd` works with any configured AI model - it just needs to read the PRD text itself, not your codebase.
 34 | </rpg-method>
 35 | 
 36 | ---
 37 | 
 38 | <overview>
 39 | <instruction>
 40 | Start with the problem, not the solution. Be specific about:
 41 | - What pain point exists?
 42 | - Who experiences it?
 43 | - Why existing solutions don't work?
 44 | - What success looks like (measurable outcomes)?
 45 | 
 46 | Keep this section focused - don't jump into implementation details yet.
 47 | </instruction>
 48 | 
 49 | ## Problem Statement
 50 | [Describe the core problem. Be concrete about user pain points.]
 51 | 
 52 | ## Target Users
 53 | [Define personas, their workflows, and what they're trying to achieve.]
 54 | 
 55 | ## Success Metrics
 56 | [Quantifiable outcomes. Examples: "80% task completion via autopilot", "< 5% manual intervention rate"]
 57 | 
 58 | </overview>
 59 | 
 60 | ---
 61 | 
 62 | <functional-decomposition>
 63 | <instruction>
 64 | Now think about CAPABILITIES (what the system DOES), not code structure yet.
 65 | 
 66 | Step 1: Identify high-level capability domains
 67 | - Think: "What major things does this system do?"
 68 | - Examples: Data Management, Core Processing, Presentation Layer
 69 | 
 70 | Step 2: For each capability, enumerate specific features
 71 | - Use explore-exploit strategy:
 72 |   * Exploit: What features are REQUIRED for core value?
 73 |   * Explore: What features make this domain COMPLETE?
 74 | 
 75 | Step 3: For each feature, define:
 76 | - Description: What it does in one sentence
 77 | - Inputs: What data/context it needs
 78 | - Outputs: What it produces/returns
 79 | - Behavior: Key logic or transformations
 80 | 
 81 | <example type="good">
 82 | Capability: Data Validation
 83 |   Feature: Schema validation
 84 |     - Description: Validate JSON payloads against defined schemas
 85 |     - Inputs: JSON object, schema definition
 86 |     - Outputs: Validation result (pass/fail) + error details
 87 |     - Behavior: Iterate fields, check types, enforce constraints
 88 | 
 89 |   Feature: Business rule validation
 90 |     - Description: Apply domain-specific validation rules
 91 |     - Inputs: Validated data object, rule set
 92 |     - Outputs: Boolean + list of violated rules
 93 |     - Behavior: Execute rules sequentially, short-circuit on failure
 94 | </example>
 95 | 
 96 | <example type="bad">
 97 | Capability: validation.js
 98 |   (Problem: This is a FILE, not a CAPABILITY. Mixing structure into functional thinking.)
 99 | 
100 | Capability: Validation
101 |   Feature: Make sure data is good
102 |   (Problem: Too vague. No inputs/outputs. Not actionable.)
103 | </example>
104 | </instruction>
105 | 
106 | ## Capability Tree
107 | 
108 | ### Capability: [Name]
109 | [Brief description of what this capability domain covers]
110 | 
111 | #### Feature: [Name]
112 | - **Description**: [One sentence]
113 | - **Inputs**: [What it needs]
114 | - **Outputs**: [What it produces]
115 | - **Behavior**: [Key logic]
116 | 
117 | #### Feature: [Name]
118 | - **Description**:
119 | - **Inputs**:
120 | - **Outputs**:
121 | - **Behavior**:
122 | 
123 | ### Capability: [Name]
124 | ...
125 | 
126 | </functional-decomposition>
127 | 
128 | ---
129 | 
130 | <structural-decomposition>
131 | <instruction>
132 | NOW think about code organization. Map capabilities to actual file/folder structure.
133 | 
134 | Rules:
135 | 1. Each capability maps to a module (folder or file)
136 | 2. Features within a capability map to functions/classes
137 | 3. Use clear module boundaries - each module has ONE responsibility
138 | 4. Define what each module exports (public interface)
139 | 
140 | The goal: Create a clear mapping between "what it does" (functional) and "where it lives" (structural).
141 | 
142 | <example type="good">
143 | Capability: Data Validation
144 |   → Maps to: src/validation/
145 |     ├── schema-validator.js      (Schema validation feature)
146 |     ├── rule-validator.js         (Business rule validation feature)
147 |     └── index.js                  (Public exports)
148 | 
149 | Exports:
150 |   - validateSchema(data, schema)
151 |   - validateRules(data, rules)
152 | </example>
153 | 
154 | <example type="bad">
155 | Capability: Data Validation
156 |   → Maps to: src/utils.js
157 |   (Problem: "utils" is not a clear module boundary. Where do I find validation logic?)
158 | 
159 | Capability: Data Validation
160 |   → Maps to: src/validation/everything.js
161 |   (Problem: One giant file. Features should map to separate files for maintainability.)
162 | </example>
163 | </instruction>
164 | 
165 | ## Repository Structure
166 | 
167 | ```
168 | project-root/
169 | ├── src/
170 | │   ├── [module-name]/       # Maps to: [Capability Name]
171 | │   │   ├── [file].js        # Maps to: [Feature Name]
172 | │   │   └── index.js         # Public exports
173 | │   └── [module-name]/
174 | ├── tests/
175 | └── docs/
176 | ```
177 | 
178 | ## Module Definitions
179 | 
180 | ### Module: [Name]
181 | - **Maps to capability**: [Capability from functional decomposition]
182 | - **Responsibility**: [Single clear purpose]
183 | - **File structure**:
184 |   ```
185 |   module-name/
186 |   ├── feature1.js
187 |   ├── feature2.js
188 |   └── index.js
189 |   ```
190 | - **Exports**:
191 |   - `functionName()` - [what it does]
192 |   - `ClassName` - [what it does]
193 | 
194 | </structural-decomposition>
195 | 
196 | ---
197 | 
198 | <dependency-graph>
199 | <instruction>
200 | This is THE CRITICAL SECTION for Task Master parsing.
201 | 
202 | Define explicit dependencies between modules. This creates the topological order for task execution.
203 | 
204 | Rules:
205 | 1. List modules in dependency order (foundation first)
206 | 2. For each module, state what it depends on
207 | 3. Foundation modules should have NO dependencies
208 | 4. Every non-foundation module should depend on at least one other module
209 | 5. Think: "What must EXIST before I can build this module?"
210 | 
211 | <example type="good">
212 | Foundation Layer (no dependencies):
213 |   - error-handling: No dependencies
214 |   - config-manager: No dependencies
215 |   - base-types: No dependencies
216 | 
217 | Data Layer:
218 |   - schema-validator: Depends on [base-types, error-handling]
219 |   - data-ingestion: Depends on [schema-validator, config-manager]
220 | 
221 | Core Layer:
222 |   - algorithm-engine: Depends on [base-types, error-handling]
223 |   - pipeline-orchestrator: Depends on [algorithm-engine, data-ingestion]
224 | </example>
225 | 
226 | <example type="bad">
227 | - validation: Depends on API
228 | - API: Depends on validation
229 | (Problem: Circular dependency. This will cause build/runtime issues.)
230 | 
231 | - user-auth: Depends on everything
232 | (Problem: Too many dependencies. Should be more focused.)
233 | </example>
234 | </instruction>
235 | 
236 | ## Dependency Chain
237 | 
238 | ### Foundation Layer (Phase 0)
239 | No dependencies - these are built first.
240 | 
241 | - **[Module Name]**: [What it provides]
242 | - **[Module Name]**: [What it provides]
243 | 
244 | ### [Layer Name] (Phase 1)
245 | - **[Module Name]**: Depends on [[module-from-phase-0], [module-from-phase-0]]
246 | - **[Module Name]**: Depends on [[module-from-phase-0]]
247 | 
248 | ### [Layer Name] (Phase 2)
249 | - **[Module Name]**: Depends on [[module-from-phase-1], [module-from-foundation]]
250 | 
251 | [Continue building up layers...]
252 | 
253 | </dependency-graph>
254 | 
255 | ---
256 | 
257 | <implementation-roadmap>
258 | <instruction>
259 | Turn the dependency graph into concrete development phases.
260 | 
261 | Each phase should:
262 | 1. Have clear entry criteria (what must exist before starting)
263 | 2. Contain tasks that can be parallelized (no inter-dependencies within phase)
264 | 3. Have clear exit criteria (how do we know phase is complete?)
265 | 4. Build toward something USABLE (not just infrastructure)
266 | 
267 | Phase ordering follows topological sort of dependency graph.
268 | 
269 | <example type="good">
270 | Phase 0: Foundation
271 |   Entry: Clean repository
272 |   Tasks:
273 |     - Implement error handling utilities
274 |     - Create base type definitions
275 |     - Setup configuration system
276 |   Exit: Other modules can import foundation without errors
277 | 
278 | Phase 1: Data Layer
279 |   Entry: Phase 0 complete
280 |   Tasks:
281 |     - Implement schema validator (uses: base types, error handling)
282 |     - Build data ingestion pipeline (uses: validator, config)
283 |   Exit: End-to-end data flow from input to validated output
284 | </example>
285 | 
286 | <example type="bad">
287 | Phase 1: Build Everything
288 |   Tasks:
289 |     - API
290 |     - Database
291 |     - UI
292 |     - Tests
293 |   (Problem: No clear focus. Too broad. Dependencies not considered.)
294 | </example>
295 | </instruction>
296 | 
297 | ## Development Phases
298 | 
299 | ### Phase 0: [Foundation Name]
300 | **Goal**: [What foundational capability this establishes]
301 | 
302 | **Entry Criteria**: [What must be true before starting]
303 | 
304 | **Tasks**:
305 | - [ ] [Task name] (depends on: [none or list])
306 |   - Acceptance criteria: [How we know it's done]
307 |   - Test strategy: [What tests prove it works]
308 | 
309 | - [ ] [Task name] (depends on: [none or list])
310 | 
311 | **Exit Criteria**: [Observable outcome that proves phase complete]
312 | 
313 | **Delivers**: [What can users/developers do after this phase?]
314 | 
315 | ---
316 | 
317 | ### Phase 1: [Layer Name]
318 | **Goal**:
319 | 
320 | **Entry Criteria**: Phase 0 complete
321 | 
322 | **Tasks**:
323 | - [ ] [Task name] (depends on: [[tasks-from-phase-0]])
324 | - [ ] [Task name] (depends on: [[tasks-from-phase-0]])
325 | 
326 | **Exit Criteria**:
327 | 
328 | **Delivers**:
329 | 
330 | ---
331 | 
332 | [Continue with more phases...]
333 | 
334 | </implementation-roadmap>
335 | 
336 | ---
337 | 
338 | <test-strategy>
339 | <instruction>
340 | Define how testing will be integrated throughout development (TDD approach).
341 | 
342 | Specify:
343 | 1. Test pyramid ratios (unit vs integration vs e2e)
344 | 2. Coverage requirements
345 | 3. Critical test scenarios
346 | 4. Test generation guidelines for Surgical Test Generator
347 | 
348 | This section guides the AI when generating tests during the RED phase of TDD.
349 | 
350 | <example type="good">
351 | Critical Test Scenarios for Data Validation module:
352 |   - Happy path: Valid data passes all checks
353 |   - Edge cases: Empty strings, null values, boundary numbers
354 |   - Error cases: Invalid types, missing required fields
355 |   - Integration: Validator works with ingestion pipeline
356 | </example>
357 | </instruction>
358 | 
359 | ## Test Pyramid
360 | 
361 | ```
362 |         /\
363 |        /E2E\       ← [X]% (End-to-end, slow, comprehensive)
364 |       /------\
365 |      /Integration\ ← [Y]% (Module interactions)
366 |     /------------\
367 |    /  Unit Tests  \ ← [Z]% (Fast, isolated, deterministic)
368 |   /----------------\
369 | ```
370 | 
371 | ## Coverage Requirements
372 | - Line coverage: [X]% minimum
373 | - Branch coverage: [X]% minimum
374 | - Function coverage: [X]% minimum
375 | - Statement coverage: [X]% minimum
376 | 
377 | ## Critical Test Scenarios
378 | 
379 | ### [Module/Feature Name]
380 | **Happy path**:
381 | - [Scenario description]
382 | - Expected: [What should happen]
383 | 
384 | **Edge cases**:
385 | - [Scenario description]
386 | - Expected: [What should happen]
387 | 
388 | **Error cases**:
389 | - [Scenario description]
390 | - Expected: [How system handles failure]
391 | 
392 | **Integration points**:
393 | - [What interactions to test]
394 | - Expected: [End-to-end behavior]
395 | 
396 | ## Test Generation Guidelines
397 | [Specific instructions for Surgical Test Generator about what to focus on, what patterns to follow, project-specific test conventions]
398 | 
399 | </test-strategy>
400 | 
401 | ---
402 | 
403 | <architecture>
404 | <instruction>
405 | Describe technical architecture, data models, and key design decisions.
406 | 
407 | Keep this section AFTER functional/structural decomposition - implementation details come after understanding structure.
408 | </instruction>
409 | 
410 | ## System Components
411 | [Major architectural pieces and their responsibilities]
412 | 
413 | ## Data Models
414 | [Core data structures, schemas, database design]
415 | 
416 | ## Technology Stack
417 | [Languages, frameworks, key libraries]
418 | 
419 | **Decision: [Technology/Pattern]**
420 | - **Rationale**: [Why chosen]
421 | - **Trade-offs**: [What we're giving up]
422 | - **Alternatives considered**: [What else we looked at]
423 | 
424 | </architecture>
425 | 
426 | ---
427 | 
428 | <risks>
429 | <instruction>
430 | Identify risks that could derail development and how to mitigate them.
431 | 
432 | Categories:
433 | - Technical risks (complexity, unknowns)
434 | - Dependency risks (blocking issues)
435 | - Scope risks (creep, underestimation)
436 | </instruction>
437 | 
438 | ## Technical Risks
439 | **Risk**: [Description]
440 | - **Impact**: [High/Medium/Low - effect on project]
441 | - **Likelihood**: [High/Medium/Low]
442 | - **Mitigation**: [How to address]
443 | - **Fallback**: [Plan B if mitigation fails]
444 | 
445 | ## Dependency Risks
446 | [External dependencies, blocking issues]
447 | 
448 | ## Scope Risks
449 | [Scope creep, underestimation, unclear requirements]
450 | 
451 | </risks>
452 | 
453 | ---
454 | 
455 | <appendix>
456 | ## References
457 | [Papers, documentation, similar systems]
458 | 
459 | ## Glossary
460 | [Domain-specific terms]
461 | 
462 | ## Open Questions
463 | [Things to resolve during development]
464 | </appendix>
465 | 
466 | ---
467 | 
468 | <task-master-integration>
469 | # How Task Master Uses This PRD
470 | 
471 | When you run `task-master parse-prd <file>.txt`, the parser:
472 | 
473 | 1. **Extracts capabilities** → Main tasks
474 |    - Each `### Capability:` becomes a top-level task
475 | 
476 | 2. **Extracts features** → Subtasks
477 |    - Each `#### Feature:` becomes a subtask under its capability
478 | 
479 | 3. **Parses dependencies** → Task dependencies
480 |    - `Depends on: [X, Y]` sets task.dependencies = ["X", "Y"]
481 | 
482 | 4. **Orders by phases** → Task priorities
483 |    - Phase 0 tasks = highest priority
484 |    - Phase N tasks = lower priority, properly sequenced
485 | 
486 | 5. **Uses test strategy** → Test generation context
487 |    - Feeds test scenarios to Surgical Test Generator during implementation
488 | 
489 | **Result**: A dependency-aware task graph that can be executed in topological order.
490 | 
491 | ## Why RPG Structure Matters
492 | 
493 | Traditional flat PRDs lead to:
494 | - ❌ Unclear task dependencies
495 | - ❌ Arbitrary task ordering
496 | - ❌ Circular dependencies discovered late
497 | - ❌ Poorly scoped tasks
498 | 
499 | RPG-structured PRDs provide:
500 | - ✅ Explicit dependency chains
501 | - ✅ Topological execution order
502 | - ✅ Clear module boundaries
503 | - ✅ Validated task graph before implementation
504 | 
505 | ## Tips for Best Results
506 | 
507 | 1. **Spend time on dependency graph** - This is the most valuable section for Task Master
508 | 2. **Keep features atomic** - Each feature should be independently testable
509 | 3. **Progressive refinement** - Start broad, use `task-master expand` to break down complex tasks
510 | 4. **Use research mode** - `task-master parse-prd --research` leverages AI for better task generation
511 | </task-master-integration>
512 | 
```
Page 38/69FirstPrevNextLast