Skip to content

Conversation

@Crunchyman-ralph
Copy link
Collaborator

@Crunchyman-ralph Crunchyman-ralph commented Oct 4, 2025

What type of PR is this?

  • πŸ› Bug fix
  • ✨ Feature
  • πŸ”Œ Integration
  • πŸ“ Docs
  • 🧹 Refactor
  • Other:

Description

Related Issues

How to Test This

# Example commands or steps

Expected result:

Contributor Checklist

  • Created changeset: npm run changeset
  • Tests pass: npm test
  • Format check passes: npm run format-check (or npm run format to fix)
  • Addressed CodeRabbit comments (if any)
  • Linked related issues (if any)
  • Manually tested the changes

Changelog Entry


For Maintainers

  • PR title follows conventional commits
  • Target branch correct
  • Labels added
  • Milestone assigned (if applicable)

Summary by CodeRabbit

  • New Features

    • Codex CLI provider (OAuth, GPT‑5/GPT‑5‑Codex), Cursor IDE slash‑commands, and a CLI Export command to push tasks to external briefs.
  • Enhancements

    • Complexity reports now enrich tasks; CLI shows colored complexity and improved next‑task display.
    • AI commands produce structured object outputs for more reliable results.
    • MCP timeout increased to 300s; subtasks get stable sequential IDs.
  • Bug Fixes

    • Parent task reverts to pending when all subtasks are pending.
    • MCP default path and connection fixes; auto‑update skipped in test env; research model renamed to sonar‑deep‑research.
  • Documentation

    • New API Keys page, Codex CLI and Claude Code guides, and Quick Start/installation updates.

Crunchyman-ralph and others added 30 commits September 22, 2025 19:25
Co-authored-by: Claude <[email protected]>
Co-authored-by: Ralph Khreish <[email protected]>
…cation (#1264)

Co-authored-by: Ralph Khreish <[email protected]>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
…es (#1262)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Ben Vargas <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 25

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (11)
tests/unit/ai-providers/openai.test.js (1)

10-18: Add mock for @ai-sdk/openai to ensure test isolation.

The test file is missing a mock for the @ai-sdk/openai package, which violates unit test isolation principles. Without this mock, the tests may be exercising the real OpenAI SDK code rather than testing the provider wrapper in isolation.

Based on learnings and coding guidelines, add the following mock before importing the provider:

 // Mock the utils module to prevent logging during tests
 jest.mock('../../../scripts/modules/utils.js', () => ({
 	log: jest.fn()
 }));
 
+// Mock the @ai-sdk/openai module
+jest.mock('@ai-sdk/openai', () => ({
+	openai: jest.fn((config) => {
+		return jest.fn((modelId) => ({
+			modelId,
+			provider: 'openai',
+			...config
+		}));
+	})
+}));
+
 // Import the provider
 import { OpenAIProvider } from '../../../src/ai-providers/openai.js';
src/ai-providers/ollama.js (1)

43-53: Clarify API key requirement logic.

The isRequiredApiKey() method returns false (indicating no API key is required), but getRequiredApiKeyName() returns 'OLLAMA_API_KEY'. This inconsistency is confusing.

If Ollama truly does not require an API key (as indicated by line 43-45 and the validateAuth implementation), consider one of the following:

Option 1: Remove getRequiredApiKeyName() if it's not needed:

-	/**
-	 * Returns the required API key environment variable name for Ollama.
-	 * @returns {string} The environment variable name
-	 */
-	getRequiredApiKeyName() {
-		return 'OLLAMA_API_KEY';
-	}

Option 2: If the method is required by the base class interface, return null or throw an error:

 	getRequiredApiKeyName() {
-		return 'OLLAMA_API_KEY';
+		return null; // Ollama does not require an API key
 	}

Option 3: If Ollama optionally supports API keys, update the comment and isRequiredApiKey() to clarify:

 	/**
-	 * Returns the required API key environment variable name for Ollama.
+	 * Returns the optional API key environment variable name for Ollama.
 	 * @returns {string} The environment variable name
 	 */
src/utils/create-mcp-config.js (1)

6-25: Add JSDoc documentation for the newly exported function.

Since formatJSONWithTabs is now part of the public API (exported at line 267), it should have JSDoc documentation explaining its purpose, parameters, return value, and the single-line array conversion behavior. This is consistent with the documentation pattern used for removeTaskMasterMCPConfiguration (lines 140-146).

Apply this diff to add documentation:

+/**
+ * Format an object as JSON string with tab indentation, converting simple arrays to single-line format
+ * @param {Object} obj - The object to format as JSON
+ * @returns {string} Formatted JSON string with tabs for indentation and simple arrays on single lines
+ */
 function formatJSONWithTabs(obj) {
 	let json = JSON.stringify(obj, null, '\t');
tests/integration/cli/complex-cross-tag-scenarios.test.js (1)

362-371: LGTM! Non-overlapping IDs prevent conflicts.

The loop correctly creates tasks with IDs 26-50 in the in-progress tag, avoiding conflicts with the master tasks (IDs 1-25). Consider adding a brief comment explaining this ID separation for clarity.

tsdown.config.ts (1)

11-18: Fix require usage in ESM module

This file is authored as an ES module (native import statements and "type": "module" packaging), so require(...) is undefined at runtime. The new version-reading block will throw before the build starts. Import readFileSync from node:fs (or use createRequire) instead of calling require directly.

Apply this diff:

-import { defineConfig } from 'tsdown';
-import { baseConfig, mergeConfig } from '@tm/build-config';
-import 'dotenv/config';
+import { defineConfig } from 'tsdown';
+import { baseConfig, mergeConfig } from '@tm/build-config';
+import { readFileSync } from 'node:fs';
+import 'dotenv/config';
@@
-		const packageJson = JSON.parse(
-			require('fs').readFileSync('package.json', 'utf8')
-		);
+		const packageJson = JSON.parse(readFileSync('package.json', 'utf8'));
scripts/modules/task-manager/update-task-by-id.js (1)

401-407: Guard against missing mainResult before dereferencing.

If the AI service returns an unexpected payload (or mainResult is missing), aiServiceResponse.mainResult becomes undefined, so the new line blows up with a TypeError before we reach the validation block. We should fail fast with a clear error instead of surfacing Cannot read properties of undefined (reading 'task').

Please add an explicit guard:

-			const updatedTask = aiServiceResponse.mainResult.task;
+			const mainResult = aiServiceResponse?.mainResult;
+			if (!mainResult || typeof mainResult !== 'object' || !mainResult.task) {
+				throw new Error('AI service returned an invalid task payload.');
+			}
+			const updatedTask = mainResult.task;
tests/unit/ai-providers/gemini-cli.test.js (1)

521-614: Complete the maxOutputTokens rename in test inputs.

We now assert that the provider calls the AI SDK with maxOutputTokens, but the test fixtures still pass maxTokens. As soon as the implementation stops aliasing maxTokens, these tests will fail (and they currently don’t cover the new option surface). The fallback assertion later in the file still expects maxTokens too.

Please update the fixtures and expectations to match the renamed parameter:

 const mockParams = {
 	...,
-	maxTokens: 100,
+	maxOutputTokens: 100,
 	temperature: 0.7
 };
 …
-					maxTokens: undefined,
+					maxOutputTokens: undefined,

Make the same change wherever else the tests create params or expectations for this option so we genuinely validate the new API surface.

src/ai-providers/gemini-cli.js (1)

430-435: Normalize maxTokens before passing to the SDK.

All three call sites now feed maxOutputTokens: params.maxTokens straight into the Vercel SDK, bypassing prepareTokenParam(). When this value is provided as a string (the CLI still surfaces strings from config/env), the provider call receives a non-numeric token limit and the request fails. Please reuse this.prepareTokenParam(...) (like the base implementation) so the limit is coerced to a safe integer before we call generateText / streamText / generateObject.

Also applies to: 531-536, 588-595

apps/cli/src/commands/list.command.ts (1)

283-323: Subtask recommendations regressed.

findNextTask still returns IDs like "12.3" for subtasks, but tasks.find((t) => t.id === '12.3') can never succeedβ€”only parents live in tasks. As a result, whenever a subtask is the best candidate, nextTask is undefined, the dashboard shows β€œNo tasks available,” and we lose the recommendation entirely. Please restore subtask handling (e.g., detect dotted IDs, look up the parent plus the specific subtask, and pass that through) before shipping.

packages/tm-core/src/storage/file-storage/file-storage.ts (1)

454-491: Parent status flips from in-progress→pending after any subtask reset
With the new allPending branch, a parent that was previously in-progress reverts to pending as soon as all subtasks happen to be back in the pending stateβ€”e.g., if one subtask is reopened the parent loses the fact that work started. Prior behavior left the parent in-progress until the final completion. Please keep the previous ordering (only transition to pending when appropriate contexts demand it) or gate the pending reset behind an explicit state.

scripts/modules/task-manager/analyze-task-complexity.js (1)

485-498: Avoid dropping existing analyses when running targeted IDs
When specificIds (or a narrow range) is used, tasksData.tasks only holds that subset. Because currentTagTaskIds is derived from this filtered list, every pre-existing analysis for other tasks in the same tag fails the currentTagTaskIds.has(...) check and gets purged from finalComplexityAnalysis. Running a targeted refresh therefore erases the rest of the reportβ€”major data loss.

Remove the extra set check (or build it from the full tag task list) so previously generated entries survive subset runs.

-				const currentTagTaskIds = new Set(tasksData.tasks.map((t) => t.id));
 				const existingEntriesNotAnalyzed =
 					existingReport.complexityAnalysis.filter(
-						(item) =>
-							!analyzedTaskIds.has(item.taskId) &&
-							currentTagTaskIds.has(item.taskId) // Only keep entries for tasks in current tag
+						(item) => !analyzedTaskIds.has(item.taskId)
 					);
♻️ Duplicate comments (1)
apps/extension/package.json (1)

279-279: Verify TypeScript version consistency.

The TypeScript version ^5.9.2 appears in multiple packages and may be a downgrade from previous versions. This should be verified for consistency across the monorepo and to ensure it's not an unintentional change.

See comment on packages/tm-core/package.json for verification script.

Comment on lines +1 to +5
---
"task-master-ai": patch
---

Improve `analyze-complexity` cli docs and `--research` flag documentation No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Optional: Address markdown formatting issues.

The changeset content is appropriate, but markdown linting flags two formatting issues:

  • Missing top-level heading (MD041)
  • Missing trailing newline (MD047)

Apply this diff to fix the formatting:

 ---
 "task-master-ai": patch
 ---
 
-Improve `analyze-complexity` cli docs and `--research` flag documentation
+# Improve analyze-complexity CLI documentation
+
+Improve `analyze-complexity` cli docs and `--research` flag documentation
+

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


5-5: Files should end with a single newline character

(MD047, single-trailing-newline)

πŸ€– Prompt for AI Agents
In .changeset/chore-fix-docs.md around lines 1-5, the changeset lacks a
top-level heading and a trailing newline; add a single top-level Markdown
heading as the very first line (e.g. "# task-master-ai: patch" or another
suitable project/semver title), keep the existing YAML block after that heading,
and save the file with a final newline so it ends with a trailing newline
character.

Comment on lines +1 to +7
---
"task-master-ai": minor
---

Add Cursor IDE custom slash command support

Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Optional: Address markdown formatting issues.

The changeset content is appropriate, but markdown linting flags two formatting issues:

  • Missing top-level heading (MD041)
  • Missing trailing newline (MD047)

Apply this diff to fix the formatting:

 ---
 "task-master-ai": minor
 ---
 
+# Add Cursor IDE custom slash command support
+
 Add Cursor IDE custom slash command support
 
 Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove.
+
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
---
"task-master-ai": minor
---
Add Cursor IDE custom slash command support
Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove.
---
"task-master-ai": minor
---
# Add Cursor IDE custom slash command support
Add Cursor IDE custom slash command support
Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove.
🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


5-5: Files should end with a single newline character

(MD047, single-trailing-newline)

πŸ€– Prompt for AI Agents
In .changeset/cursor-slash-commands.md around lines 1 to 7, the changeset is
missing a top-level heading and a trailing newline; add a single H1 heading
(e.g., "# Cursor Slash Commands" or similar descriptive title) as the first
non-metadata line and ensure the file ends with a newline character so the
markdown linter no longer reports MD041 and MD047.

Comment on lines +1 to +5
---
"task-master-ai": patch
---

Change parent task back to "pending" when all subtasks are in "pending" state
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Optional: Address markdown formatting issues.

The changeset content is appropriate, but markdown linting flags two formatting issues:

  • Missing top-level heading (MD041)
  • Missing trailing newline (MD047)

Apply this diff to fix the formatting:

 ---
 "task-master-ai": patch
 ---
 
-Change parent task back to "pending" when all subtasks are in "pending" state
+# Change parent task state to pending when all subtasks are pending
+
+Change parent task back to "pending" when all subtasks are in "pending" state
+

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


5-5: Files should end with a single newline character

(MD047, single-trailing-newline)

πŸ€– Prompt for AI Agents
In .changeset/curvy-weeks-flow.md around lines 1 to 5, the changeset is missing
a top-level heading and a trailing newline; add a top-level heading (e.g., "#
Patch: task-master-ai") as the first line, ensure the existing YAML block and
description remain, and add a single trailing newline at the end of the file so
the file ends with a newline character.

"task-master-ai": patch
---

Do a quick fix on build
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Clarify the changeset summary

Changeset entries should be user-facing, concise, and written in imperative mood. β€œDo a quick fix on build” reads like an internal note and doesn’t tell consumers what improved. Please rephrase with a clear action, e.g., β€œFix the build configuration for task-master-ai.”

🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

πŸ€– Prompt for AI Agents
.changeset/easy-spiders-wave.md around line 5: the changeset summary "Do a quick
fix on build" is vague and not user-facing; replace it with a concise,
imperative, consumer-focused sentence that describes the actual change (for
example, "Fix build configuration for task-master-ai" or "Fix CI build step for
task-master-ai"), preserving tone and brevity so the entry communicates what
changed to package consumers.

"task-master-ai": minor
---

Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

Use imperative voice in the changeset summary

Per the repo’s changeset guidelines, summaries should be user-facing and written in the imperative mood. Please rewrite this line accordingly (e.g., β€œAdd API keys page to docs at docs.task-master.dev/getting-started/api-keys”).

-Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys
+Add API keys page to docs website: docs.task-master.dev/getting-started/api-keys
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys
Add API keys page to docs website: docs.task-master.dev/getting-started/api-keys
🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

πŸ€– Prompt for AI Agents
In .changeset/flat-cities-say.md at line 5, the changeset summary is not written
in the imperative voice; rewrite the sentence to be user-facing and imperative
(for example: "Add API keys page to docs at
docs.task-master.dev/getting-started/api-keys") so it follows the repository's
changeset guidelines.

Comment on lines +4 to +13
const PRDSingleTaskSchema = z.object({
id: z.number().int().positive(),
title: z.string().min(1),
description: z.string().min(1),
details: z.string().nullable(),
testStrategy: z.string().nullable(),
priority: z.enum(['high', 'medium', 'low']).nullable(),
dependencies: z.array(z.number().int().positive()).nullable(),
status: z.string().nullable()
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Consider adding default values for nullable fields.

The schema defines priority, dependencies, and status as nullable without defaults, which could lead to inconsistent task data. For consistency with BaseTaskSchema (in src/schemas/base-schemas.js), consider:

  1. dependencies (line 11): Should default to [] for consistency with task conventions
  2. status (line 12): Should default to 'pending' to ensure all tasks have a status
  3. priority (line 10): Nullable is acceptable, but consider defaulting to null explicitly

Apply this diff to add defaults:

 const PRDSingleTaskSchema = z.object({
 	id: z.number().int().positive(),
 	title: z.string().min(1),
 	description: z.string().min(1),
 	details: z.string().nullable(),
 	testStrategy: z.string().nullable(),
-	priority: z.enum(['high', 'medium', 'low']).nullable(),
-	dependencies: z.array(z.number().int().positive()).nullable(),
-	status: z.string().nullable()
+	priority: z.enum(['high', 'medium', 'low']).nullable().default(null),
+	dependencies: z.array(z.number().int().positive()).default([]),
+	status: z.string().default('pending')
 });
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const PRDSingleTaskSchema = z.object({
id: z.number().int().positive(),
title: z.string().min(1),
description: z.string().min(1),
details: z.string().nullable(),
testStrategy: z.string().nullable(),
priority: z.enum(['high', 'medium', 'low']).nullable(),
dependencies: z.array(z.number().int().positive()).nullable(),
status: z.string().nullable()
});
const PRDSingleTaskSchema = z.object({
id: z.number().int().positive(),
title: z.string().min(1),
description: z.string().min(1),
details: z.string().nullable(),
testStrategy: z.string().nullable(),
priority: z.enum(['high', 'medium', 'low']).nullable().default(null),
dependencies: z.array(z.number().int().positive()).default([]),
status: z.string().default('pending')
});
πŸ€– Prompt for AI Agents
In src/schemas/parse-prd.js around lines 4 to 13, the PRDSingleTaskSchema marks
priority, dependencies, and status as nullable but does not provide defaults;
update the schema so dependencies defaults to an empty array, status defaults to
'pending', and priority explicitly defaults to null (keep it nullable) by
chaining .default(...) on each respective field to ensure consistent task
objects across the app.

Comment on lines +265 to +267

// Export the formatting function for use by other modules
export { formatJSONWithTabs };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify test coverage and usage of the exported function.

As per coding guidelines, utility functions must meet 90% test coverage. Since formatJSONWithTabs is now exported and part of the public API, ensure that comprehensive tests exist covering:

  • Basic formatting with tabs
  • Single-line array conversion for simple arrays
  • Preservation of nested structures in arrays
  • Edge cases (empty objects, nested objects, etc.)

Additionally, verify that there is actual usage or planned usage of this export in other modules, as no importing files are shown in the provided context.

Run the following script to check for test coverage and usage:


🏁 Script executed:

#!/bin/bash
# Description: Verify test coverage for formatJSONWithTabs and check for external usage

# Search for test files covering this function
echo "=== Searching for tests of formatJSONWithTabs ==="
rg -n "formatJSONWithTabs" --type=js -g "*test*" -g "*spec*"

# Search for imports of this function from other modules
echo -e "\n=== Searching for imports of formatJSONWithTabs from other modules ==="
rg -n "import.*formatJSONWithTabs.*from.*create-mcp-config" --type=js

# Alternative: search for any usage of the function outside this file
echo -e "\n=== Searching for any external usage ==="
rg -n "formatJSONWithTabs" --type=js -g "!src/utils/create-mcp-config.js"

Length of output: 402


Add tests for formatJSONWithTabs and confirm its import usage

  • No test currently imports or invokes formatJSONWithTabs; add tests covering basic tab formatting, single-line arrays, nested structures, and edge cases (empty objects, nested objects, etc.).
  • Verify correct import and usage in src/profiles/roo.js:9.
πŸ€– Prompt for AI Agents
In src/utils/create-mcp-config.js around lines 265-267, add unit tests that
import the named export formatJSONWithTabs and cover basic tab formatting,
single-line arrays, nested structures, empty objects, and deeply nested objects
and arrays (edge cases), asserting exact string output for each; create a test
file (e.g., tests/utils/formatJSONWithTabs.test.js) that imports the function
with the same named import as exported and includes cases for tabs count
variations and null/undefined handling; also open src/profiles/roo.js line 9 and
verify the import path and syntax match the named export (export {
formatJSONWithTabs }) β€” if it currently uses a default import or wrong path,
change it to a named import from the correct relative path and update any call
sites to pass expected arguments so tests and runtime use are consistent.

describe('Large Task Set Performance', () => {
it('should handle large task sets efficiently', () => {
// Create a large task set (100 tasks)
// Create a large task set (50 tasks)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

LGTM! Consider adding more context.

The comment accurately reflects the reduced task set size. Consider expanding it to mention the distribution (e.g., "50 tasks total: 25 in master with dependencies, 25 in in-progress") for better test documentation.

πŸ€– Prompt for AI Agents
In tests/integration/cli/complex-cross-tag-scenarios.test.js around line 333,
the inline comment "// Create a large task set (50 tasks)" should be expanded to
document the task distribution; update it to something like "Create a large task
set (50 tasks total: 25 in master with dependencies, 25 in in-progress)" or
similar wording that specifies how the 50 tasks are split and any important
dependency relationships so the test intent is clearer.

Comment on lines +374 to 378
// Execute move; correctness is validated below (no timing assertion)
execSync(
`node ${binPath} move --from=50 --from-tag=master --to-tag=in-progress --with-dependencies`,
`node ${binPath} move --from=25 --from-tag=master --to-tag=in-progress --with-dependencies`,
{ stdio: 'pipe' }
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

Update test description to match its purpose.

The test execution is correct, but the test description "should handle large task sets efficiently" implies performance testing. Since timing assertions were removed (as noted in line 374), consider renaming to something like "should handle large task sets correctly" or "should move large dependency chains".

Apply this diff to update the test description:

-	it('should handle large task sets efficiently', () => {
+	it('should handle large task sets correctly', () => {
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Execute move; correctness is validated below (no timing assertion)
execSync(
`node ${binPath} move --from=50 --from-tag=master --to-tag=in-progress --with-dependencies`,
`node ${binPath} move --from=25 --from-tag=master --to-tag=in-progress --with-dependencies`,
{ stdio: 'pipe' }
);
it('should handle large task sets correctly', () => {
// Execute move; correctness is validated below (no timing assertion)
execSync(
`node ${binPath} move --from=25 --from-tag=master --to-tag=in-progress --with-dependencies`,
{ stdio: 'pipe' }
);
πŸ€– Prompt for AI Agents
In tests/integration/cli/complex-cross-tag-scenarios.test.js around lines 374 to
378, the test title still reads "should handle large task sets efficiently"
which implies performance assertions that were removed; update the test
description to reflect correctness rather than performance (e.g., "should handle
large task sets correctly" or "should move large dependency chains") by changing
the test/title string accordingly so it matches the actual behavior being
validated by the execSync move call.

Comment on lines +382 to +399

// Verify all tasks in the dependency chain were moved
for (let i = 1; i <= 25; i++) {
expect(tasksAfter.master.tasks.find((t) => t.id === i)).toBeUndefined();
expect(
tasksAfter['in-progress'].tasks.find((t) => t.id === i)
).toBeDefined();
}

// Verify in-progress still has its original tasks (26-50)
for (let i = 26; i <= 50; i++) {
expect(
tasksAfter['in-progress'].tasks.find((t) => t.id === i)
).toBeDefined();
}

// Final count check
expect(tasksAfter['in-progress'].tasks).toHaveLength(50); // 25 moved + 25 original
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

LGTM! Comprehensive verification logic.

The verification correctly checks:

  1. Tasks 1-25 are removed from master and present in in-progress
  2. Tasks 26-50 remain in in-progress
  3. Final count is 50 (25 moved + 25 original)

Minor style suggestion: Line 382 contains an unnecessary blank line that could be removed for cleaner code.

πŸ€– Prompt for AI Agents
In tests/integration/cli/complex-cross-tag-scenarios.test.js around lines 382 to
399 there is an unnecessary blank line at line 382; remove that blank line so
the verification block is contiguous and the surrounding comments/code flow
cleanly, then run the test suite to ensure formatting-only change passes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
packages/tm-core/src/repositories/supabase-task-repository.ts (2)

20-29: Minor: Validation schema includes non-persisted fields.

The TaskUpdateSchema validates details and testStrategy fields (lines 26-27), but these are explicitly skipped when persisting to the database (line 182). This creates a disconnect where validation suggests these fields are supported, but they are silently discarded.

Consider one of these approaches:

Option 1: Remove non-persisted fields from validation schema (preferred if these fields aren't used):

 const TaskUpdateSchema = z
 	.object({
 		title: z.string().min(1).optional(),
 		description: z.string().optional(),
 		status: TaskStatusSchema.optional(),
 		priority: z.enum(['low', 'medium', 'high', 'critical']).optional(),
-		details: z.string().optional(),
-		testStrategy: z.string().optional()
 	})
 	.partial();

Option 2: Add a comment explaining why these fields are validated but not persisted:

 const TaskUpdateSchema = z
 	.object({
 		title: z.string().min(1).optional(),
 		description: z.string().optional(),
 		status: TaskStatusSchema.optional(),
 		priority: z.enum(['low', 'medium', 'high', 'critical']).optional(),
+		// Note: details and testStrategy are validated for Task interface compatibility
+		// but not persisted to the database (stored elsewhere or computed)
 		details: z.string().optional(),
 		testStrategy: z.string().optional()
 	})
 	.partial();

Also applies to: 182-182


9-17: Critical: TaskStatusSchema allows unsupported statuses

  • Schema permits seven values, but the database enum (database.types.ts:405) only supports 'todo', 'in_progress', and 'done'.
  • mapStatusToDatabase handles only 'pending', 'in-progress', and 'done', throwing for others.
  • Remove unsupported statuses (review, deferred, cancelled, blocked) from TaskStatusSchema or, if needed, extend both the DB enum and mapStatusToDatabase to cover all seven.
scripts/modules/commands.js (1)

3621-3680: Restore Azure/Vertex provider hint handling

The provider-flag check and setModel hint mapping now omit --azure and --vertex. As a result, specifying those flags no longer prevents conflicts, and more importantly, the CLI stops sending the provider hint, so setting Azure or Vertex models fails. This regresses existing functionality. Please restore the Azure/Vertex branches alongside the new Codex CLI path.

-	const providerFlags = [
-		options.openrouter,
-		options.ollama,
-		options.bedrock,
-		options.claudeCode,
-		options.geminiCli,
-		options.codexCli
-	].filter(Boolean).length;
+	const providerFlags = [
+		options.openrouter,
+		options.ollama,
+		options.bedrock,
+		options.claudeCode,
+		options.azure,
+		options.vertex,
+		options.geminiCli,
+		options.codexCli
+	].filter(Boolean).length;
@@
-						providerHint: options.openrouter
-							? 'openrouter'
-							: options.ollama
-								? 'ollama'
-								: options.bedrock
-									? 'bedrock'
-									: options.claudeCode
-										? 'claude-code'
-										: options.geminiCli
-											? 'gemini-cli'
-											: options.codexCli
-												? 'codex-cli'
-												: undefined
+						providerHint: options.openrouter
+							? CUSTOM_PROVIDERS.OPENROUTER
+							: options.ollama
+								? CUSTOM_PROVIDERS.OLLAMA
+								: options.bedrock
+									? CUSTOM_PROVIDERS.BEDROCK
+									: options.claudeCode
+										? CUSTOM_PROVIDERS.CLAUDE_CODE
+										: options.azure
+											? CUSTOM_PROVIDERS.AZURE
+											: options.vertex
+												? CUSTOM_PROVIDERS.VERTEX
+												: options.geminiCli
+													? CUSTOM_PROVIDERS.GEMINI_CLI
+													: options.codexCli
+														? CUSTOM_PROVIDERS.CODEX_CLI
+														: undefined

Be sure to apply the same mapping fix to the --set-research and --set-fallback branches.

Also applies to: 3665-3738

src/ai-providers/gemini-cli.js (1)

479-485: Normalize usage tokens consistently.

Here (and in the manual generateObject retry) you only read promptTokens/completionTokens. When the SDK returns the newer { inputTokens, outputTokens } shape, both values become undefined, so telemetry and cost accounting break. Mirror the base-class normalisation so both formats are supported.

-			return {
-				text: finalText,
-				usage: {
-					inputTokens: result.usage?.promptTokens,
-					outputTokens: result.usage?.completionTokens,
-					totalTokens: result.usage?.totalTokens
-				}
-			};
+			const inputTokens =
+				result.usage?.inputTokens ?? result.usage?.promptTokens ?? 0;
+			const outputTokens =
+				result.usage?.outputTokens ?? result.usage?.completionTokens ?? 0;
+			const totalTokens =
+				result.usage?.totalTokens ?? inputTokens + outputTokens;
+
+			return {
+				text: finalText,
+				usage: { inputTokens, outputTokens, totalTokens }
+			};

Make the corresponding change around Line 620 for the object-generation fallback to keep both paths in sync.

src/ai-providers/base-provider.js (1)

149-201: Restore maxTokens when piping limits to AI SDK text calls
prepareTokenParam now emits only maxOutputTokens. The text/stream helpers in this repo (and upstream SDK) still rely on maxTokens, so limits silently vanishβ€”requests can run uncapped and spike cost. Please send both fields to preserve existing behaviour.

 	prepareTokenParam(modelId, maxTokens) {
 		if (maxTokens === undefined) {
 			return {};
 		}
 
 		// Ensure maxTokens is an integer
 		const tokenValue = Math.floor(Number(maxTokens));
 
-		return { maxOutputTokens: tokenValue };
+		return { maxTokens: tokenValue, maxOutputTokens: tokenValue };
 	}
♻️ Duplicate comments (2)
README.md (1)

109-109: Add Windows path for Q CLI entry.

The Q CLI row in the MCP table only shows the Unix/macOS path (~/.aws/amazonq/mcp.json). The manual configuration header update on line 113 indicates Q Developer CLI support, but Windows users lack equivalent path guidance.

As noted in the previous review, consider adding the Windows equivalent path (e.g., %USERPROFILE%\.aws\amazonq\mcp.json) to complete the cross-platform documentation, consistent with other rows in the table.

Also applies to: 113-113

src/ai-providers/claude-code.js (1)

89-109: Reinstate Anthropic env isolation before creating the Claude Code client
We already learned the hard way that ai-sdk-provider-claude-code will happily consume any ambient ANTHROPIC_API_KEY, charging the wrong account. The new getClient dropped the temporary override/restore flow we previously agreed on, so a globally configured Anthropic key will leak into Claudeβ€―Code again. Please wrap createClaudeCode in the same sandbox as before: stash the original ANTHROPIC_API_KEY, temporarily set/delete it based on CLAUDE_CODE_API_KEY (or the passed apiKey), and restore it in a finally.

 	getClient(params = {}) {
 		try {
 			const settings =
 				getClaudeCodeSettingsForCommand(params.commandName) || {};
-
-			return createClaudeCode({
-				defaultSettings: settings
-			});
+			const originalAnthropic = process.env.ANTHROPIC_API_KEY;
+			const claudeCodeKey =
+				params.apiKey || process.env.CLAUDE_CODE_API_KEY || null;
+
+			const restoreAnthropicEnv = () => {
+				if (originalAnthropic !== undefined) {
+					process.env.ANTHROPIC_API_KEY = originalAnthropic;
+				} else {
+					delete process.env.ANTHROPIC_API_KEY;
+				}
+			};
+
+			try {
+				if (claudeCodeKey) {
+					process.env.ANTHROPIC_API_KEY = claudeCodeKey;
+				} else if (originalAnthropic !== undefined) {
+					delete process.env.ANTHROPIC_API_KEY;
+				}
+
+				return createClaudeCode({
+					defaultSettings: settings
+				});
+			} finally {
+				restoreAnthropicEnv();
+			}
 		} catch (error) {
 			// Provide more helpful error message
πŸ“œ Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 86027f1 and 4b54738.

β›” Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
πŸ“’ Files selected for processing (27)
  • .changeset/brave-lions-sing.md (1 hunks)
  • CLAUDE.md (1 hunks)
  • README.md (3 hunks)
  • docs/command-reference.md (1 hunks)
  • docs/configuration.md (2 hunks)
  • docs/examples/codex-cli-usage.md (1 hunks)
  • docs/models.md (5 hunks)
  • docs/providers/codex-cli.md (1 hunks)
  • package.json (7 hunks)
  • packages/tm-core/src/repositories/supabase-task-repository.ts (1 hunks)
  • scripts/modules/ai-services-unified.js (5 hunks)
  • scripts/modules/commands.js (7 hunks)
  • scripts/modules/config-manager.js (13 hunks)
  • scripts/modules/supported-models.json (2 hunks)
  • scripts/modules/task-manager/models.js (2 hunks)
  • src/ai-providers/base-provider.js (6 hunks)
  • src/ai-providers/claude-code.js (1 hunks)
  • src/ai-providers/codex-cli.js (1 hunks)
  • src/ai-providers/gemini-cli.js (4 hunks)
  • src/ai-providers/grok-cli.js (1 hunks)
  • src/ai-providers/index.js (1 hunks)
  • src/constants/providers.js (1 hunks)
  • tests/integration/providers/temperature-support.test.js (1 hunks)
  • tests/unit/ai-providers/base-provider.test.js (1 hunks)
  • tests/unit/ai-providers/codex-cli.test.js (1 hunks)
  • tests/unit/ai-services-unified.test.js (4 hunks)
  • tests/unit/config-manager.test.js (4 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (28)
docs/**/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/new_features.mdc)

Add feature documentation to '/docs' folder, include tagged system usage examples, update command reference documentation, and provide migration notes if relevant.

Files:

  • docs/providers/codex-cli.md
  • docs/models.md
  • docs/examples/codex-cli-usage.md
  • docs/configuration.md
  • docs/command-reference.md
tests/{unit,integration,e2e,fixtures}/**/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Test files must be organized as follows: unit tests in tests/unit/, integration tests in tests/integration/, end-to-end tests in tests/e2e/, and test fixtures in tests/fixtures/.

Files:

  • tests/unit/config-manager.test.js
  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/integration/providers/temperature-support.test.js
  • tests/unit/ai-providers/codex-cli.test.js
tests/unit/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Each module should have a corresponding unit test file in tests/unit/ that reflects the module structure (one test file per module).

Files:

  • tests/unit/config-manager.test.js
  • tests/unit/ai-services-unified.test.js
**/*.{test,spec}.{js,ts,jsx,tsx}

πŸ“„ CodeRabbit inference engine (.cursor/rules/git_workflow.mdc)

**/*.{test,spec}.{js,ts,jsx,tsx}: Create a test file and ensure all tests pass when all subtasks are complete; commit tests if added or modified
When all subtasks are complete, run final testing using the appropriate test runner (e.g., npm test, jest, or manual testing)

Files:

  • tests/unit/config-manager.test.js
  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/integration/providers/temperature-support.test.js
  • tests/unit/ai-providers/codex-cli.test.js
**/*.test.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

**/*.test.js: Never use asynchronous operations in tests. Make all mocks return synchronous values when possible.
Always mock tests properly based on the way the tested functions are defined and used.
Follow the test file organization: mocks must be set up before importing modules under test, and spies on mocked modules should be set up after imports.
Use fixtures from tests/fixtures/ for consistent sample data across tests.
Always declare mocks before importing the modules being tested in Jest test files.
Use jest.spyOn() after imports to create spies on mock functions and reference these spies in test assertions.
When testing functions with callbacks, get the callback from your mock's call arguments, execute it directly with test inputs, and verify the results.
For ES modules, use jest.mock() before static imports and jest.unstable_mockModule() before dynamic imports to mock dependencies.
Reset mock functions (mockFn.mockReset()) before dynamic imports if they might have been called previously.
When verifying console assertions, assert against the actual arguments passed (single formatted string), not multiple arguments.
Use mock-fs to mock file system operations in tests, and restore the file system after each test.
Mock API calls (e.g., Anthropic/Claude) by mocking the entire module and providing predictable responses.
Set mock environment variables in test setup and restore them after each test.
Maintain test fixtures separate from test logic.
Follow the mock-first-then-import pattern for all Jest mocks.
Do not define mock variables before jest.mock() calls (they won't be accessible due to hoisting).
Use test-specific file paths (e.g., 'test-tasks.json') for all file operations in tests.
Mock readJSON and writeJSON to avoid real file system interactions in tests.
Verify file operations use the correct paths in expect statements.
Use different file paths for each test to avoid test interdependence.
Verify modifications on the in-memory task objects passed to w...

Files:

  • tests/unit/config-manager.test.js
  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/integration/providers/temperature-support.test.js
  • tests/unit/ai-providers/codex-cli.test.js
tests/unit/**/*.test.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

tests/unit/**/*.test.js: Unit tests must be located in tests/unit/, test individual functions and utilities in isolation, mock all external dependencies, and keep tests small, focused, and fast.
Do not include actual command execution in unit tests.

Files:

  • tests/unit/config-manager.test.js
  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/unit/ai-providers/codex-cli.test.js
tests/{unit,integration,e2e}/**/*.test.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

tests/{unit,integration,e2e}/**/*.test.js: When testing CLI commands built with Commander.js, test the command action handlers directly rather than trying to mock the entire Commander.js chain.
When mocking the Commander.js chain, mock ALL chainable methods (option, argument, action, on, etc.) and return this (or the mock object) from all chainable method mocks.
Explicitly handle all options, including defaults and shorthand flags (e.g., -p for --prompt), and include null/undefined checks in test implementations for parameters that might be optional.
Do not try to use the real action implementation without proper mocking, and do not mock Commander partiallyβ€”either mock it completely or test the action directly.
Mock the action handlers for CLI commands and verify they're called with correct arguments.
Use sample task fixtures for consistent test data, mock file system operations, and test both success and error paths for task operations.
Mock console output and verify correct formatting in UI function tests. Use flexible assertions like toContain() or toMatch() for formatted output.
Mock chalk functions to return the input text to make testing easier while still verifying correct function calls.

Files:

  • tests/unit/config-manager.test.js
  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/integration/providers/temperature-support.test.js
  • tests/unit/ai-providers/codex-cli.test.js
**/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

**/*.js: Declare and initialize global variables at the top of modules to avoid hoisting issues.
Use proper function declarations to avoid hoisting issues and initialize variables before they are referenced.
Do not reference variables before their declaration in module scope.
Use dynamic imports (import()) to avoid initialization order issues in modules.

Files:

  • tests/unit/config-manager.test.js
  • src/ai-providers/grok-cli.js
  • tests/unit/ai-providers/base-provider.test.js
  • scripts/modules/task-manager/models.js
  • src/constants/providers.js
  • scripts/modules/ai-services-unified.js
  • src/ai-providers/codex-cli.js
  • scripts/modules/config-manager.js
  • src/ai-providers/base-provider.js
  • tests/unit/ai-services-unified.test.js
  • src/ai-providers/index.js
  • tests/integration/providers/temperature-support.test.js
  • src/ai-providers/gemini-cli.js
  • scripts/modules/commands.js
  • src/ai-providers/claude-code.js
  • tests/unit/ai-providers/codex-cli.test.js
**/*.{test,spec}.*

πŸ“„ CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

Test files should follow naming conventions: .test., .spec., or _test. depending on the language

Files:

  • tests/unit/config-manager.test.js
  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/integration/providers/temperature-support.test.js
  • tests/unit/ai-providers/codex-cli.test.js
tests/{unit,integration,e2e}/**

πŸ“„ CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

Organize test directories by test type (unit, integration, e2e) and mirror source structure where possible

Files:

  • tests/unit/config-manager.test.js
  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/integration/providers/temperature-support.test.js
  • tests/unit/ai-providers/codex-cli.test.js
src/ai-providers/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)

src/ai-providers/*.js: Create a new provider module file in src/ai-providers/ named .js when adding a new AI provider.
Provider modules must export three functions: generateText, streamText, and generateObject.
Provider modules must import the provider's create function from @ai-sdk/, and import generateText, streamText, generateObject from the core ai package, as well as the log utility from ../../scripts/modules/utils.js.
Implement generateText, streamText, and generateObject functions in provider modules with basic validation and try/catch error handling.

Provider-specific wrappers for Vercel AI SDK functions must be implemented in src/ai-providers/*.js, each file corresponding to a provider.

Files:

  • src/ai-providers/grok-cli.js
  • src/ai-providers/codex-cli.js
  • src/ai-providers/base-provider.js
  • src/ai-providers/index.js
  • src/ai-providers/gemini-cli.js
  • src/ai-providers/claude-code.js
tests/unit/ai-providers/*.test.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)

Create unit tests for the new provider in tests/unit/ai-providers/.test.js, mocking @ai-sdk/ and core ai module functions, and testing all exported functions for correct behavior and error handling.

Files:

  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-providers/codex-cli.test.js
.changeset/*.md

πŸ“„ CodeRabbit inference engine (.cursor/rules/changeset.mdc)

.changeset/*.md: When running npm run changeset or npx changeset add, provide a concise summary of the changes for the CHANGELOG.md in imperative mood, typically a single line, and not a detailed Git commit message.
The changeset summary should be user-facing, describing what changed in the released version that is relevant to users or consumers of the package.
Do not use your detailed Git commit message body as the changeset summary.

Files:

  • .changeset/brave-lions-sing.md
.changeset/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/new_features.mdc)

Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.

Files:

  • .changeset/brave-lions-sing.md
scripts/modules/task-manager/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_services.mdc)

scripts/modules/task-manager/*.js: Centralize all LLM calls through generateTextService or generateObjectService.
Do not import or call anything from the old ai-services.js, ai-client-factory.js, or ai-client-utils.js files.
Do not initialize AI clients (Anthropic, Perplexity, etc.) directly within core logic (task-manager/) or MCP direct functions.
Do not fetch AI-specific parameters (model ID, max tokens, temp) using config-manager.js getters for the AI call. Pass the role instead.
Do not implement fallback or retry logic outside ai-services-unified.js.
Do not handle API key resolution outside the service layer (it uses utils.js internally).
Determine the appropriate role (main, research, fallback) in your core logic and pass it to the service.
Pass the session object (received in the context parameter, especially from direct function wrappers) to the service call when in MCP context.
Use generateTextService and implement robust manual JSON parsing (with Zod validation after parsing) when structured output is needed, as generateObjectService has shown unreliability with some providers/schemas.
Be aware of potential reliability issues with generateObjectService across different providers and complex schemas. Prefer generateTextService + manual parsing as a more robust alternative for structured data needs.

Files in scripts/modules/task-manager/ should each handle a specific action related to task management (e.g., add-task.js, expand-task.js), supporting the tagged task lists system and backward compatibility.

Files:

  • scripts/modules/task-manager/models.js
scripts/modules/**

πŸ“„ CodeRabbit inference engine (.cursor/rules/dev_workflow.mdc)

When using the MCP server, restart it if core logic in scripts/modules or MCP tool/direct function definitions change.

Files:

  • scripts/modules/task-manager/models.js
  • scripts/modules/ai-services-unified.js
  • scripts/modules/supported-models.json
  • scripts/modules/config-manager.js
  • scripts/modules/commands.js
scripts/modules/task-manager/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/tags.mdc)

scripts/modules/task-manager/*: All core functions in scripts/modules/task-manager/ must accept a context parameter and use it to extract projectRoot and tag
All core functions in scripts/modules/task-manager/ must use readJSON(tasksPath, projectRoot, tag) and writeJSON(tasksPath, data, projectRoot, tag)

Files:

  • scripts/modules/task-manager/models.js
scripts/modules/task-manager/**/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/telemetry.mdc)

scripts/modules/task-manager/**/*.js: Functions in scripts/modules/task-manager/ that invoke AI services must call the appropriate AI service function (e.g., generateObjectService), passing commandName and outputType in the params object.
Core logic functions in scripts/modules/task-manager/ must return an object that includes aiServiceResponse.telemetryData.
If the core logic function handles CLI output (outputFormat === 'text' or 'cli'), and aiServiceResponse.telemetryData is available, it must call displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli') from scripts/modules/ui.js.

Do not call AI-specific getters (like getMainModelId, getMainMaxTokens) from core logic functions in scripts/modules/task-manager/*; instead, pass the role to the unified AI service.

Files:

  • scripts/modules/task-manager/models.js
scripts/modules/ai-services-unified.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)

Integrate the new provider module with scripts/modules/ai-services-unified.js by importing it and adding an entry to the PROVIDER_FUNCTIONS map.

scripts/modules/ai-services-unified.js: Centralize all LLM calls through generateTextService or generateObjectService.
Do not import or call anything from the old ai-services.js, ai-client-factory.js, or ai-client-utils.js files.
Do not fetch AI-specific parameters (model ID, max tokens, temp) using config-manager.js getters for the AI call. Pass the role instead.
Do not implement fallback or retry logic outside ai-services-unified.js.
Do not handle API key resolution outside the service layer (it uses utils.js internally).

The telemetryData object returned by ai-services-unified.js must include the fields: timestamp, userId, commandName, modelUsed, providerName, inputTokens, outputTokens, totalTokens, totalCost, and currency.

Files:

  • scripts/modules/ai-services-unified.js
scripts/modules/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Each module in scripts/modules/ should be focused on a single responsibility, following the modular architecture (e.g., commands.js for CLI command handling, task-manager.js for task data and core logic, dependency-manager.js for dependency management, ui.js for CLI output formatting, ai-services-unified.js for AI service integration, config-manager.js for configuration management, utils.js for utility functions).

scripts/modules/*.js: Export all core functions, helper functions, and utility methods needed by your new function or command from their respective modules. Explicitly review the module's export block to ensure every required dependency is included.
Pass all required parameters to functions you call within your implementation and verify that direct function parameters match their core function counterparts.
Use consistent file naming conventions: 'task_${id.toString().padStart(3, '0')}.txt', use path.join for composing file paths, and use appropriate file extensions (.txt for tasks, .json for data).
Use structured error objects with code and message properties, include clear error messages, and handle both function-specific and file system errors.
Import all silent mode utilities together from 'scripts/modules/utils.js' and always use isSilentMode() to check global silent mode status. Wrap core function calls within direct functions using enableSilentMode() and disableSilentMode() in a try/finally block if the core function might produce console output.
Core functions should check outputFormat === 'text' before displaying UI elements and use internal logging that respects silent mode.
Design functions to accept dependencies as parameters (dependency injection) and avoid hard-coded dependencies that are difficult to mock.
Keep pure logic separate from I/O operations or UI rendering to allow testing the logic without mocking complex dependencies.
When implementing core logic for new features, do so in 'scripts/modules/' before CLI or MCP interfaces, and d...

Files:

  • scripts/modules/ai-services-unified.js
  • scripts/modules/config-manager.js
  • scripts/modules/commands.js
scripts/modules/ai-services*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/new_features.mdc)

Ensure AI calls correctly handle and propagate telemetryData as described in 'telemetry.mdc'.

Files:

  • scripts/modules/ai-services-unified.js
scripts/modules/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/tags.mdc)

scripts/modules/*: Every command that reads or writes tasks.json must be tag-aware
All command files must import getCurrentTag from utils.js
Every CLI command that operates on tasks must include the --tag CLI option
All commands must resolve the tag using the pattern: options.tag || getCurrentTag(projectRoot) || 'master'
All commands must find projectRoot with error handling before proceeding
All commands must pass { projectRoot, tag } as context to core functions
MCP direct functions must accept and use a context object containing projectRoot and tag, and pass them to core functions
Do not hard-code tag resolution (e.g., const tag = options.tag || 'master';); always use getCurrentTag
Do not omit the --tag CLI option in commands that operate on tasks
Do not omit the context parameter when calling core functions from commands
Do not call readJSON or writeJSON without passing projectRoot and tag

Files:

  • scripts/modules/ai-services-unified.js
  • scripts/modules/supported-models.json
  • scripts/modules/config-manager.js
  • scripts/modules/commands.js
package.json

πŸ“„ CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

Add and update test scripts in package.json to include test, test:watch, test:coverage, test:unit, test:integration, test:e2e, and test:ci

Files:

  • package.json
scripts/modules/supported-models.json

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)

Add a new key for the provider and an array of model objects under it in scripts/modules/supported-models.json, including id, name, allowed_roles, and optionally swe_score, cost_per_1m_tokens, and max_tokens.

Files:

  • scripts/modules/supported-models.json
scripts/modules/config-manager.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)

scripts/modules/config-manager.js: Update scripts/modules/config-manager.js to add the new provider to MODEL_MAP, ensure it is included in VALID_PROVIDERS, and update API key handling logic.
If adding Ollama or another provider not requiring an API key, add a specific check at the beginning of isApiKeySet and getMcpApiKeyStatus in scripts/modules/config-manager.js to return true immediately for that provider.

scripts/modules/config-manager.js: Import and use specific getters from scripts/modules/config-manager.js to access configuration values needed for application logic; pass the explicitRoot parameter to getters if calling from MCP direct functions.
Use isApiKeySet(providerName, session) from config-manager.js to check if a provider's key is available before attempting an AI call.
Handle potential ConfigurationError if the .taskmasterconfig file is missing or invalid when accessed via getConfig.

Files:

  • scripts/modules/config-manager.js
tests/integration/**/*.test.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

Integration tests must be located in tests/integration/, test interactions between modules, and focus on component interfaces rather than implementation details.

Files:

  • tests/integration/providers/temperature-support.test.js
tests/{integration,e2e}/**/*.test.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

Properly mock session objects when required by functions, and reset environment variables between tests if modified.

Files:

  • tests/integration/providers/temperature-support.test.js
scripts/modules/commands.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_services.mdc)

scripts/modules/commands.js: Centralize all LLM calls through generateTextService or generateObjectService.
Do not import or call anything from the old ai-services.js, ai-client-factory.js, or ai-client-utils.js files.
Do not fetch AI-specific parameters (model ID, max tokens, temp) using config-manager.js getters for the AI call. Pass the role instead.
Do not implement fallback or retry logic outside ai-services-unified.js.
Do not handle API key resolution outside the service layer (it uses utils.js internally).
Determine the appropriate role (main, research, fallback) in your core logic and pass it to the service.
Pass the session object (received in the context parameter, especially from direct function wrappers) to the service call when in MCP context.
Use generateTextService and implement robust manual JSON parsing (with Zod validation after parsing) when structured output is needed, as generateObjectService has shown unreliability with some providers/schemas.
Be aware of potential reliability issues with generateObjectService across different providers and complex schemas. Prefer generateTextService + manual parsing as a more robust alternative for structured data needs.

scripts/modules/commands.js: All new user-facing commands should be added to 'scripts/modules/commands.js'.
Use consistent patterns for option naming and help text in CLI commands.
Follow the Commander.js model for subcommand structure in CLI commands.
When using callbacks (like in Commander.js commands), define them separately to allow testing the callback logic independently.
Add help text to the command definition and update 'dev_workflow.mdc' with command reference when adding a new feature.
Follow the established pattern in 'commands.js' for CLI command implementation, using Commander.js for argument parsing, including comprehensive help text and examples, and supporting tagged task context awareness.
Provide clear error messages for common failu...

Files:

  • scripts/modules/commands.js
🧠 Learnings (34)
πŸ““ Common learnings
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1262
File: scripts/modules/task-manager/update-tasks.js:216-233
Timestamp: 2025-10-01T19:53:34.261Z
Learning: For scripts/modules/task-manager/*.js: Use generateObjectService with Zod schemas for structured AI responses rather than generateTextService + manual JSON parsing, as modern AI providers increasingly support the tool use and generateObject paradigm with improved reliability.
πŸ“š Learning: 2025-07-18T17:07:39.336Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-07-18T17:07:39.336Z
Learning: Applies to src/ai-providers/*.js : Provider-specific wrappers for Vercel AI SDK functions must be implemented in src/ai-providers/*.js, each file corresponding to a provider.

Applied to files:

  • src/ai-providers/grok-cli.js
πŸ“š Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to src/ai-providers/*.js : Provider modules must import the provider's create<ProviderName> function from ai-sdk/<provider-name>, and import generateText, streamText, generateObject from the core ai package, as well as the log utility from ../../scripts/modules/utils.js.

Applied to files:

  • src/ai-providers/grok-cli.js
  • package.json
  • src/ai-providers/codex-cli.js
  • tests/unit/ai-services-unified.test.js
  • src/ai-providers/index.js
  • src/ai-providers/gemini-cli.js
  • tests/unit/ai-providers/codex-cli.test.js
πŸ“š Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to tests/unit/ai-providers/*.test.js : Create unit tests for the new provider in tests/unit/ai-providers/<provider-name>.test.js, mocking ai-sdk/<provider-name> and core ai module functions, and testing all exported functions for correct behavior and error handling.

Applied to files:

  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/integration/providers/temperature-support.test.js
  • tests/unit/ai-providers/codex-cli.test.js
πŸ“š Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to src/ai-providers/*.js : Implement generate<ProviderName>Text, stream<ProviderName>Text, and generate<ProviderName>Object functions in provider modules with basic validation and try/catch error handling.

Applied to files:

  • tests/unit/ai-providers/base-provider.test.js
  • src/ai-providers/base-provider.js
  • tests/unit/ai-services-unified.test.js
πŸ“š Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to **/*.test.js : Do not import real AI service clients in tests; create fully mocked versions that return predictable responses.

Applied to files:

  • tests/unit/ai-providers/base-provider.test.js
  • tests/unit/ai-services-unified.test.js
  • tests/unit/ai-providers/codex-cli.test.js
πŸ“š Learning: 2025-09-24T15:12:58.855Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/AGENTS.md:0-0
Timestamp: 2025-09-24T15:12:58.855Z
Learning: Applies to assets/**/.mcp.json : Configure the Task Master MCP server in .mcp.json under mcpServers.task-master-ai using npx task-master-ai and provide required API key env vars

Applied to files:

  • docs/configuration.md
  • README.md
πŸ“š Learning: 2025-07-18T17:10:12.881Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:12.881Z
Learning: For CLI usage, install Taskmaster globally with `npm install -g task-master-ai` or use locally via `npx task-master-ai ...`.

Applied to files:

  • README.md
  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-31T22:08:16.039Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/taskmaster.mdc:0-0
Timestamp: 2025-07-31T22:08:16.039Z
Learning: Applies to {.env,.cursor/mcp.json} : Set API keys for AI providers (e.g., ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.) in your .env file in the project root (for CLI use) or within the env section of your .cursor/mcp.json file (for MCP/Cursor integration).

Applied to files:

  • README.md
πŸ“š Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to .cursor/mcp.json.example : Add the new PROVIDER_API_KEY with its placeholder to the env section for taskmaster-ai in .cursor/mcp.json.example.

Applied to files:

  • README.md
πŸ“š Learning: 2025-09-29T13:33:46.952Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1246
File: src/ai-providers/claude-code.js:40-42
Timestamp: 2025-09-29T13:33:46.952Z
Learning: Claude Code provider should use CLAUDE_CODE_API_KEY environment variable instead of automatically picking up ANTHROPIC_API_KEY to avoid conflicts, since the ai-sdk-provider-claude-code package follows standard Anthropic patterns and prioritizes API keys over OAuth authentication, which can cause unexpected API charges.

Applied to files:

  • README.md
  • src/ai-providers/claude-code.js
πŸ“š Learning: 2025-07-31T22:08:16.039Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/taskmaster.mdc:0-0
Timestamp: 2025-07-31T22:08:16.039Z
Learning: Applies to .cursor/mcp.json : When using MCP/Cursor integration, ensure that the required API keys are present in the env section of .cursor/mcp.json.

Applied to files:

  • README.md
πŸ“š Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to {.env,.cursor/mcp.json} : Store API keys only in `.env` (for CLI, loaded by `dotenv` in `scripts/dev.js`) or `.cursor/mcp.json` (for MCP, accessed via `session.env`).

Applied to files:

  • README.md
πŸ“š Learning: 2025-07-18T17:10:12.881Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:12.881Z
Learning: Applies to {.env,.cursor/mcp.json} : Store sensitive API keys and specific endpoint URLs in the `.env` file in the project root for CLI usage, or in the `env` section of `.cursor/mcp.json` for MCP/Cursor integration. Do not store non-API key settings in these files.

Applied to files:

  • README.md
πŸ“š Learning: 2025-07-18T17:10:02.683Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:02.683Z
Learning: Applies to {.env,.cursor/mcp.json} : Store sensitive API keys and endpoint URLs for Taskmaster in a `.env` file (for CLI usage) or in the `env` section of `.cursor/mcp.json` (for MCP/Cursor integration). Do not store non-API key settings in these files.

Applied to files:

  • README.md
πŸ“š Learning: 2025-08-03T12:13:33.875Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-08-03T12:13:33.875Z
Learning: Applies to package.json : Add and update test scripts in package.json to include test, test:watch, test:coverage, test:unit, test:integration, test:e2e, and test:ci

Applied to files:

  • package.json
πŸ“š Learning: 2025-09-26T19:03:33.225Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: package.json:130-132
Timestamp: 2025-09-26T19:03:33.225Z
Learning: In the eyaltoledano/claude-task-master repository, packages are bundled using tsdown during the build process, which means dependencies imported by the source code (including tm internal packages like tm/ai-sdk-provider-grok-cli) are included in the final bundle and don't need to be available as separate runtime dependencies, so they should remain as devDependencies rather than being moved to dependencies.

Applied to files:

  • package.json
πŸ“š Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to scripts/modules/supported-models.json : Add a new key for the provider and an array of model objects under it in scripts/modules/supported-models.json, including id, name, allowed_roles, and optionally swe_score, cost_per_1m_tokens, and max_tokens.

Applied to files:

  • scripts/modules/supported-models.json
πŸ“š Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to scripts/modules/config-manager.js : Update scripts/modules/config-manager.js to add the new provider to MODEL_MAP, ensure it is included in VALID_PROVIDERS, and update API key handling logic.

Applied to files:

  • scripts/modules/config-manager.js
πŸ“š Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to **/*.test.js : Never use asynchronous operations in tests. Make all mocks return synchronous values when possible.

Applied to files:

  • CLAUDE.md
πŸ“š Learning: 2025-07-18T17:10:53.657Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/glossary.mdc:0-0
Timestamp: 2025-07-18T17:10:53.657Z
Learning: Guidelines for implementing and maintaining tests for Task Master CLI (tests.mdc).

Applied to files:

  • CLAUDE.md
πŸ“š Learning: 2025-08-11T12:30:23.843Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-11T12:30:23.843Z
Learning: Import Task Master's development workflow commands and guidelines; treat the contents of ./.taskmaster/CLAUDE.md as if included in the main CLAUDE.md

Applied to files:

  • CLAUDE.md
πŸ“š Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to tests/{unit,integration,e2e}/**/*.test.js : Use sample task fixtures for consistent test data, mock file system operations, and test both success and error paths for task operations.

Applied to files:

  • CLAUDE.md
πŸ“š Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to **/*.test.js : Follow the test file organization: mocks must be set up before importing modules under test, and spies on mocked modules should be set up after imports.

Applied to files:

  • CLAUDE.md
πŸ“š Learning: 2025-07-18T17:07:39.336Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-07-18T17:07:39.336Z
Learning: Applies to tests/{unit,integration,e2e,fixtures}/**/*.js : Test files must be organized as follows: unit tests in tests/unit/, integration tests in tests/integration/, end-to-end tests in tests/e2e/, and test fixtures in tests/fixtures/.

Applied to files:

  • CLAUDE.md
πŸ“š Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/**/*.test.js : Test core logic independently with both data formats, mock file system operations, test tag resolution behavior, and verify migration compatibility in unit tests.

Applied to files:

  • CLAUDE.md
πŸ“š Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/**/*.test.js : Test CLI and MCP interfaces with real task data, verify end-to-end workflows across tag contexts, and test error scenarios and recovery in integration tests.

Applied to files:

  • CLAUDE.md
πŸ“š Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to **/*.test.js : Mock API calls (e.g., Anthropic/Claude) by mocking the entire module and providing predictable responses.

Applied to files:

  • tests/unit/ai-services-unified.test.js
  • tests/unit/ai-providers/codex-cli.test.js
πŸ“š Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to src/ai-providers/*.js : Create a new provider module file in src/ai-providers/ named <provider-name>.js when adding a new AI provider.

Applied to files:

  • src/ai-providers/index.js
πŸ“š Learning: 2025-07-18T17:06:57.833Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-07-18T17:06:57.833Z
Learning: Ensure `.taskmasterconfig` exists and has valid provider/model IDs for the roles you intend to use (manage via `task-master models --setup`).

Applied to files:

  • docs/command-reference.md
πŸ“š Learning: 2025-07-31T22:08:16.039Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/taskmaster.mdc:0-0
Timestamp: 2025-07-31T22:08:16.039Z
Learning: Applies to .taskmaster/config.json : All other Taskmaster settings (model choice, max tokens, temperature, log level, custom endpoints) are managed in .taskmaster/config.json via the task-master models command or models MCP tool.

Applied to files:

  • docs/command-reference.md
  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/commands.js : Use consistent patterns for option naming and help text in CLI commands.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-09-29T13:33:46.952Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1246
File: src/ai-providers/claude-code.js:40-42
Timestamp: 2025-09-29T13:33:46.952Z
Learning: Claude Code provider should use environment variable isolation to control API key access, temporarily managing ANTHROPIC_API_KEY during client creation to prevent the ai-sdk-provider-claude-code package from automatically picking up API keys intended for other providers, while allowing explicit CLAUDE_CODE_API_KEY usage as a fallback to OAuth authentication.

Applied to files:

  • src/ai-providers/claude-code.js
πŸ“š Learning: 2025-09-29T13:33:46.952Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1246
File: src/ai-providers/claude-code.js:40-42
Timestamp: 2025-09-29T13:33:46.952Z
Learning: Claude Code provider should use environment variable isolation to temporarily manage ANTHROPIC_API_KEY during client creation: if CLAUDE_CODE_API_KEY is set, temporarily set ANTHROPIC_API_KEY to that value; if CLAUDE_CODE_API_KEY is not set but ANTHROPIC_API_KEY exists, temporarily unset ANTHROPIC_API_KEY to force OAuth mode. This prevents the ai-sdk-provider-claude-code package from accidentally using API keys intended for the regular Anthropic provider while still allowing explicit API key usage as a fallback.

Applied to files:

  • src/ai-providers/claude-code.js
🧬 Code graph analysis (14)
tests/unit/config-manager.test.js (1)
tests/unit/config-manager.test.mjs (1)
  • DEFAULT_CONFIG (61-90)
src/ai-providers/grok-cli.js (2)
packages/ai-sdk-provider-grok-cli/src/grok-cli-provider.ts (1)
  • GrokCliProvider (13-35)
src/ai-providers/base-provider.js (1)
  • BaseAIProvider (16-377)
tests/unit/ai-providers/base-provider.test.js (1)
src/ai-providers/base-provider.js (1)
  • BaseAIProvider (16-377)
scripts/modules/task-manager/models.js (2)
mcp-server/src/core/direct-functions/models.js (1)
  • providerHint (41-41)
src/constants/providers.js (2)
  • CUSTOM_PROVIDERS (18-29)
  • CUSTOM_PROVIDERS (18-29)
scripts/modules/ai-services-unified.js (5)
src/ai-providers/codex-cli.js (1)
  • CodexCliProvider (15-106)
scripts/modules/config-manager.js (2)
  • providerName (704-704)
  • modelId (703-703)
scripts/modules/update-config-tokens.js (2)
  • modelId (25-25)
  • modelData (29-31)
scripts/modules/task-manager/parse-prd/parse-prd-streaming.js (1)
  • modelId (236-236)
scripts/modules/task-manager/models.js (1)
  • modelData (426-426)
src/ai-providers/codex-cli.js (2)
src/ai-providers/base-provider.js (1)
  • BaseAIProvider (16-377)
scripts/modules/config-manager.js (3)
  • settings (445-445)
  • settings (455-455)
  • settings (471-471)
scripts/modules/config-manager.js (2)
src/constants/commands.js (2)
  • AI_COMMAND_NAMES (7-17)
  • AI_COMMAND_NAMES (7-17)
src/constants/providers.js (2)
  • CUSTOM_PROVIDERS (18-29)
  • CUSTOM_PROVIDERS (18-29)
src/ai-providers/base-provider.js (4)
scripts/modules/task-manager/parse-prd/parse-prd-streaming.js (3)
  • inputTokens (592-593)
  • result (559-568)
  • outputTokens (589-591)
scripts/modules/ai-services-unified.js (2)
  • result (430-430)
  • totalTokens (894-894)
scripts/modules/task-manager/parse-prd/parse-prd-helpers.js (1)
  • outputTokens (278-280)
scripts/modules/task-manager/parse-prd/parse-prd.js (1)
  • outputTokens (154-154)
tests/unit/ai-services-unified.test.js (2)
tests/unit/config-manager.test.mjs (1)
  • mockResolveEnvVariable (44-44)
scripts/modules/ai-services-unified.js (1)
  • result (430-430)
tests/integration/providers/temperature-support.test.js (4)
src/ai-providers/claude-code.js (1)
  • ClaudeCodeProvider (30-129)
src/ai-providers/codex-cli.js (1)
  • CodexCliProvider (15-106)
src/ai-providers/gemini-cli.js (1)
  • GeminiCliProvider (14-651)
src/ai-providers/grok-cli.js (1)
  • GrokCliProvider (10-83)
src/ai-providers/gemini-cli.js (1)
src/ai-providers/base-provider.js (1)
  • BaseAIProvider (16-377)
scripts/modules/commands.js (1)
scripts/modules/task-manager/models.js (4)
  • options (149-149)
  • options (277-277)
  • options (368-368)
  • options (656-656)
src/ai-providers/claude-code.js (2)
src/ai-providers/base-provider.js (1)
  • BaseAIProvider (16-377)
scripts/modules/config-manager.js (4)
  • settings (445-445)
  • settings (455-455)
  • settings (471-471)
  • modelId (703-703)
tests/unit/ai-providers/codex-cli.test.js (1)
src/ai-providers/codex-cli.js (1)
  • CodexCliProvider (15-106)
πŸͺ› markdownlint-cli2 (0.18.1)
docs/providers/codex-cli.md

92-92: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


350-350: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


355-355: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


360-360: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


374-374: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


379-379: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


385-385: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


400-400: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


405-405: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


410-410: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


412-412: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


444-444: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


454-454: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


469-469: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


478-478: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


487-487: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

.changeset/brave-lions-sing.md

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

docs/configuration.md

443-443: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


448-448: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


450-450: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


455-455: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


458-458: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


462-462: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


518-518: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


540-540: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

CLAUDE.md

9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


14-14: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

Comment on lines +7 to +27
## Test Guidelines

### Synchronous Tests
- **NEVER use async/await in test functions** unless testing actual asynchronous operations
- Use synchronous top-level imports instead of dynamic `await import()`
- Test bodies should be synchronous whenever possible
- Example:
```javascript
// βœ… CORRECT - Synchronous imports
import { MyClass } from '../src/my-class.js';

it('should verify behavior', () => {
expect(new MyClass().property).toBe(value);
});

// ❌ INCORRECT - Async imports
it('should verify behavior', async () => {
const { MyClass } = await import('../src/my-class.js');
expect(new MyClass().property).toBe(value);
});
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix markdownlint violations in new section.

markdownlint is failing this block (MD022, MD031). Add a blank line before the ## Test Guidelines heading and surround the fenced code block with blank lines so the list item renders correctly.

-**Import Task Master's development workflow commands and guidelines, treat as if import is in the main CLAUDE.md file.**
-@./.taskmaster/CLAUDE.md
-
-## Test Guidelines
+**Import Task Master's development workflow commands and guidelines, treat as if import is in the main CLAUDE.md file.**
+@./.taskmaster/CLAUDE.md
+
+
+## Test Guidelines
@@
-- Example:
-  ```javascript
+- Example:
+
+  ```javascript
@@
-  ```
+  ```
+
🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


14-14: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

πŸ€– Prompt for AI Agents
In CLAUDE.md around lines 7 to 27, the new "## Test Guidelines" section is
causing markdownlint errors (MD022, MD031) because there is no blank line before
the heading and the fenced code block inside the list item isn’t surrounded by
blank lines; add a single blank line immediately before the "## Test Guidelines"
heading, and insert a blank line after the "Example:" list item line and another
blank line after the closing ``` fence (preserving list indentation) so the
fenced code block is separated from the list and renders correctly.

Comment on lines +433 to +581
### Codex CLI Provider

The Codex CLI provider integrates Task Master with OpenAI's Codex CLI, allowing you to use ChatGPT subscription models via OAuth authentication.

1. **Prerequisites**:
- Node.js >= 18
- Codex CLI >= 0.42.0 (>= 0.44.0 recommended)
- ChatGPT subscription: Plus, Pro, Business, Edu, or Enterprise (for OAuth access to GPT-5 models)

2. **Installation**:
```bash
npm install -g @openai/codex
```

3. **Authentication** (OAuth - Primary Method):
```bash
codex login
```
This will open a browser window for OAuth authentication with your ChatGPT account. Once authenticated, Task Master will automatically use these credentials.

4. **Optional API Key Method**:
While OAuth is the primary and recommended authentication method, you can optionally set an OpenAI API key:
```bash
# In .env file
OPENAI_API_KEY=sk-your-openai-api-key-here
```
**Note**: The API key will only be injected if explicitly provided. OAuth is always preferred.

5. **Configuration**:
```json
// In .taskmaster/config.json
{
"models": {
"main": {
"provider": "codex-cli",
"modelId": "gpt-5-codex",
"maxTokens": 128000,
"temperature": 0.2
},
"fallback": {
"provider": "codex-cli",
"modelId": "gpt-5",
"maxTokens": 128000,
"temperature": 0.2
}
},
"codexCli": {
"allowNpx": true,
"skipGitRepoCheck": true,
"approvalMode": "on-failure",
"sandboxMode": "workspace-write"
}
}
```

6. **Available Models**:
- `gpt-5` - Latest GPT-5 model (272K max input, 128K max output)
- `gpt-5-codex` - GPT-5 optimized for agentic software engineering (272K max input, 128K max output)

7. **Codex CLI Settings (`codexCli` section)**:

The `codexCli` section in your configuration file supports the following options:

- **`allowNpx`** (boolean, default: `false`): Allow fallback to `npx @openai/codex` if CLI not found on PATH
- **`skipGitRepoCheck`** (boolean, default: `false`): Skip git repository safety check (recommended for CI/non-repo usage)
- **`approvalMode`** (string): Control command execution approval
- `"untrusted"`: Require approval for all commands
- `"on-failure"`: Only require approval after a command fails (default)
- `"on-request"`: Approve only when explicitly requested
- `"never"`: Never require approval (not recommended)
- **`sandboxMode`** (string): Control filesystem access
- `"read-only"`: Read-only access
- `"workspace-write"`: Allow writes to workspace (default)
- `"danger-full-access"`: Full filesystem access (use with caution)
- **`codexPath`** (string, optional): Custom path to codex CLI executable
- **`cwd`** (string, optional): Working directory for Codex CLI execution
- **`fullAuto`** (boolean, optional): Fully automatic mode (equivalent to `--full-auto` flag)
- **`dangerouslyBypassApprovalsAndSandbox`** (boolean, optional): Bypass all safety checks (dangerous!)
- **`color`** (string, optional): Color handling - `"always"`, `"never"`, or `"auto"`
- **`outputLastMessageFile`** (string, optional): Write last agent message to specified file
- **`verbose`** (boolean, optional): Enable verbose logging
- **`env`** (object, optional): Additional environment variables for Codex CLI

8. **Command-Specific Settings** (optional):
You can override settings for specific Task Master commands:
```json
{
"codexCli": {
"allowNpx": true,
"approvalMode": "on-failure",
"commandSpecific": {
"parse-prd": {
"approvalMode": "never",
"verbose": true
},
"expand": {
"sandboxMode": "read-only"
}
}
}
}
```

9. **Codebase Features**:
The Codex CLI provider is codebase-capable, meaning it can analyze and interact with your project files. Codebase analysis features are automatically enabled when using `codex-cli` as your provider and `enableCodebaseAnalysis` is set to `true` in your global configuration (default).

10. **Setup Commands**:
```bash
# Set Codex CLI for main role
task-master models --set-main gpt-5-codex --codex-cli

# Set Codex CLI for fallback role
task-master models --set-fallback gpt-5 --codex-cli

# Verify configuration
task-master models
```

11. **Troubleshooting**:

**"codex: command not found" error:**
- Install Codex CLI globally: `npm install -g @openai/codex`
- Verify installation: `codex --version`
- Alternatively, enable `allowNpx: true` in your codexCli configuration

**"Not logged in" errors:**
- Run `codex login` to authenticate with your ChatGPT account
- Verify authentication status: `codex` (opens interactive CLI)

**"Old version" warnings:**
- Check version: `codex --version`
- Upgrade: `npm install -g @openai/codex@latest`
- Minimum version: 0.42.0, recommended: >= 0.44.0

**"Model not available" errors:**
- Only `gpt-5` and `gpt-5-codex` are available via OAuth subscription
- Verify your ChatGPT subscription is active
- For other OpenAI models, use the standard `openai` provider with an API key

**API key not being used:**
- API key is only injected when explicitly provided
- OAuth authentication is always preferred
- If you want to use an API key, ensure `OPENAI_API_KEY` is set in your `.env` file

12. **Important Notes**:
- OAuth subscription required for model access (no API key needed for basic operation)
- Limited to OAuth-available models only (`gpt-5` and `gpt-5-codex`)
- Pricing information is not available for OAuth models (shows as "Unknown" in cost calculations)
- See [Codex CLI Provider Documentation](./providers/codex-cli.md) for more details
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

LGTM! Comprehensive Codex CLI provider documentation.

The Codex CLI Provider section is thorough, covering prerequisites, authentication, configuration, models, features, and troubleshooting. Well-organized for user reference.

Optional: Fix markdown formatting issues.

Static analysis detected missing blank lines around several fenced code blocks (lines 443, 448, 450, 455, 458, 462, 518, 540). While minor, adding blank lines would improve markdown consistency:

 2. **Installation**:
+
    ```bash
    npm install -g @openai/codex
    ```
+
 3. **Authentication** (OAuth - Primary Method):

Apply similar fixes to other flagged locations for consistency with markdown best practices.

🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

443-443: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


448-448: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


450-450: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


455-455: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


458-458: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


462-462: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


518-518: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


540-540: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

πŸ€– Prompt for AI Agents
docs/configuration.md lines 433-581: Several fenced code blocks lack surrounding
blank lines (reported at ~443, 448, 450, 455, 458, 462, 518, 540); update the
markdown by ensuring there is a blank line before each opening ``` and a blank
line after each closing ``` for those blocks (and any other fenced blocks in
this range) so the fenced code blocks are properly separated from surrounding
text and render consistently.

Comment on lines +1 to +510
# Codex CLI Provider

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.

## Why Use Codex CLI?

The primary benefits of using the `codex-cli` provider include:

- **Use Latest OpenAI Models**: Access to cutting-edge models like GPT-5 and GPT-5-Codex via ChatGPT subscription
- **OAuth Authentication**: No API key management needed - authenticate once with `codex login`
- **Built-in Tool Execution**: Native support for command execution, file changes, MCP tools, and web search
- **Native JSON Schema Support**: Structured output generation without post-processing
- **Approval/Sandbox Modes**: Fine-grained control over command execution and filesystem access for safety

## Quickstart

Get up and running with Codex CLI in 3 steps:

```bash
# 1. Install Codex CLI globally
npm install -g @openai/codex

# 2. Authenticate with your ChatGPT account
codex login

# 3. Configure Task Master to use Codex CLI
task-master models --set-main gpt-5-codex --codex-cli
```

## Requirements

- **Node.js**: >= 18.0.0
- **Codex CLI**: >= 0.42.0 (>= 0.44.0 recommended)
- **ChatGPT Subscription**: Required for OAuth access (Plus, Pro, Business, Edu, or Enterprise)
- **Task Master**: >= 0.27.3 (version with Codex CLI support)

### Checking Your Versions

```bash
# Check Node.js version
node --version

# Check Codex CLI version
codex --version

# Check Task Master version
task-master --version
```

## Installation

### Install Codex CLI

```bash
# Install globally via npm
npm install -g @openai/codex

# Verify installation
codex --version
```

Expected output: `v0.44.0` or higher

### Install Task Master (if not already installed)

```bash
# Install globally
npm install -g task-master-ai

# Or install in your project
npm install --save-dev task-master-ai
```

## Authentication

### OAuth Authentication (Primary Method - Recommended)

The Codex CLI provider is designed to use OAuth authentication with your ChatGPT subscription:

```bash
# Launch Codex CLI and authenticate
codex login
```

This will:
1. Open a browser window for OAuth authentication
2. Prompt you to log in with your ChatGPT account
3. Store authentication credentials locally
4. Allow Task Master to automatically use these credentials

To verify your authentication:
```bash
# Open interactive Codex CLI
codex

# Use /about command to see auth status
/about
```

### Optional: API Key Method

While OAuth is the primary and recommended method, you can optionally use an OpenAI API key:

```bash
# In your .env file
OPENAI_CODEX_API_KEY=sk-your-openai-api-key-here
```

**Important Notes**:
- The API key will **only** be injected when explicitly provided
- OAuth authentication is always preferred when available
- Using an API key doesn't provide access to subscription-only models like GPT-5-Codex
- For full OpenAI API access with non-subscription models, consider using the standard `openai` provider instead
- `OPENAI_CODEX_API_KEY` is specific to the codex-cli provider to avoid conflicts with the `openai` provider's `OPENAI_API_KEY`

## Available Models

The Codex CLI provider supports only models available through ChatGPT subscription:

| Model ID | Description | Max Input Tokens | Max Output Tokens |
|----------|-------------|------------------|-------------------|
| `gpt-5` | Latest GPT-5 model | 272K | 128K |
| `gpt-5-codex` | GPT-5 optimized for agentic software engineering | 272K | 128K |

**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.

**Research Capabilities**: Both GPT-5 models support web search tools, making them suitable for the `research` role in addition to `main` and `fallback` roles.

## Configuration

### Basic Configuration

Add Codex CLI to your `.taskmaster/config.json`:

```json
{
"models": {
"main": {
"provider": "codex-cli",
"modelId": "gpt-5-codex",
"maxTokens": 128000,
"temperature": 0.2
},
"fallback": {
"provider": "codex-cli",
"modelId": "gpt-5",
"maxTokens": 128000,
"temperature": 0.2
}
}
}
```

### Advanced Configuration with Codex CLI Settings

The `codexCli` section allows you to customize Codex CLI behavior:

```json
{
"models": {
"main": {
"provider": "codex-cli",
"modelId": "gpt-5-codex",
"maxTokens": 128000,
"temperature": 0.2
}
},
"codexCli": {
"allowNpx": true,
"skipGitRepoCheck": true,
"approvalMode": "on-failure",
"sandboxMode": "workspace-write",
"verbose": false
}
}
```

### Codex CLI Settings Reference

#### Core Settings

- **`allowNpx`** (boolean, default: `false`)
- Allow fallback to `npx @openai/codex` if the CLI is not found on PATH
- Useful for CI environments or systems without global npm installations
- Example: `"allowNpx": true`

- **`skipGitRepoCheck`** (boolean, default: `false`)
- Skip git repository safety check before execution
- Recommended for CI environments or non-repository usage
- Example: `"skipGitRepoCheck": true`

#### Execution Control

- **`approvalMode`** (string)
- Controls when to require user approval for command execution
- Options:
- `"untrusted"`: Require approval for all commands
- `"on-failure"`: Only require approval after a command fails (default)
- `"on-request"`: Approve only when explicitly requested
- `"never"`: Never require approval (use with caution)
- Example: `"approvalMode": "on-failure"`

- **`sandboxMode`** (string)
- Controls filesystem access permissions
- Options:
- `"read-only"`: Read-only access to filesystem
- `"workspace-write"`: Allow writes to workspace directory (default)
- `"danger-full-access"`: Full filesystem access (use with extreme caution)
- Example: `"sandboxMode": "workspace-write"`

#### Path and Environment

- **`codexPath`** (string, optional)
- Custom path to Codex CLI executable
- Useful when Codex is installed in a non-standard location
- Example: `"codexPath": "/usr/local/bin/codex"`

- **`cwd`** (string, optional)
- Working directory for Codex CLI execution
- Defaults to current working directory
- Example: `"cwd": "/path/to/project"`

- **`env`** (object, optional)
- Additional environment variables for Codex CLI
- Example: `"env": { "DEBUG": "true" }`

#### Advanced Settings

- **`fullAuto`** (boolean, optional)
- Fully automatic mode (equivalent to `--full-auto` flag)
- Bypasses most approvals for fully automated workflows
- Example: `"fullAuto": true`

- **`dangerouslyBypassApprovalsAndSandbox`** (boolean, optional)
- Bypass all safety checks including approvals and sandbox
- **WARNING**: Use with extreme caution - can execute arbitrary code
- Example: `"dangerouslyBypassApprovalsAndSandbox": false`

- **`color`** (string, optional)
- Force color handling in Codex CLI output
- Options: `"always"`, `"never"`, `"auto"`
- Example: `"color": "auto"`

- **`outputLastMessageFile`** (string, optional)
- Write last agent message to specified file
- Useful for debugging or logging
- Example: `"outputLastMessageFile": "./last-message.txt"`

- **`verbose`** (boolean, optional)
- Enable verbose provider logging
- Helpful for debugging issues
- Example: `"verbose": true`

### Command-Specific Settings

Override settings for specific Task Master commands:

```json
{
"codexCli": {
"allowNpx": true,
"approvalMode": "on-failure",
"commandSpecific": {
"parse-prd": {
"approvalMode": "never",
"verbose": true
},
"expand": {
"sandboxMode": "read-only"
},
"add-task": {
"approvalMode": "untrusted"
}
}
}
}
```

## Usage

### Setting Codex CLI Models

```bash
# Set Codex CLI for main role
task-master models --set-main gpt-5-codex --codex-cli

# Set Codex CLI for fallback role
task-master models --set-fallback gpt-5 --codex-cli

# Set Codex CLI for research role
task-master models --set-research gpt-5 --codex-cli

# Verify configuration
task-master models
```

### Using Codex CLI with Task Master Commands

Once configured, use Task Master commands as normal:

```bash
# Parse a PRD with Codex CLI
task-master parse-prd my-requirements.txt

# Analyze project complexity
task-master analyze-complexity --research

# Expand a task into subtasks
task-master expand --id=1.2

# Add a new task with AI assistance
task-master add-task --prompt="Implement user authentication" --research
```

The provider will automatically use your OAuth credentials when Codex CLI is configured.

## Codebase Features

The Codex CLI provider is **codebase-capable**, meaning it can analyze and interact with your project files. This enables advanced features like:

- **Code Analysis**: Understanding your project structure and dependencies
- **Intelligent Suggestions**: Context-aware task recommendations
- **File Operations**: Reading and analyzing project files for better task generation
- **Pattern Recognition**: Identifying common patterns and best practices in your codebase

### Enabling Codebase Analysis

Codebase analysis is automatically enabled when:
1. Your provider is set to `codex-cli`
2. `enableCodebaseAnalysis` is `true` in your global configuration (default)

To verify or configure:

```json
{
"global": {
"enableCodebaseAnalysis": true
}
}
```

## Troubleshooting

### "codex: command not found" Error

**Symptoms**: Task Master reports that the Codex CLI is not found.

**Solutions**:
1. **Install Codex CLI globally**:
```bash
npm install -g @openai/codex
```

2. **Verify installation**:
```bash
codex --version
```

3. **Alternative: Enable npx fallback**:
```json
{
"codexCli": {
"allowNpx": true
}
}
```

### "Not logged in" Errors

**Symptoms**: Authentication errors when trying to use Codex CLI.

**Solutions**:
1. **Authenticate with OAuth**:
```bash
codex login
```

2. **Verify authentication status**:
```bash
codex
# Then use /about command
```

3. **Re-authenticate if needed**:
```bash
# Logout first
codex
# Use /auth command to change auth method

# Then login again
codex login
```

### "Old version" Warnings

**Symptoms**: Warnings about Codex CLI version being outdated.

**Solutions**:
1. **Check current version**:
```bash
codex --version
```

2. **Upgrade to latest version**:
```bash
npm install -g @openai/codex@latest
```

3. **Verify upgrade**:
```bash
codex --version
```
Should show >= 0.44.0

### "Model not available" Errors

**Symptoms**: Error indicating the requested model is not available.

**Causes and Solutions**:

1. **Using unsupported model**:
- Only `gpt-5` and `gpt-5-codex` are available via Codex CLI
- For other OpenAI models, use the standard `openai` provider

2. **Subscription not active**:
- Verify your ChatGPT subscription is active
- Check subscription status at <https://platform.openai.com>

3. **Wrong provider selected**:
- Verify you're using `--codex-cli` flag when setting models
- Check `.taskmaster/config.json` shows `"provider": "codex-cli"`

### API Key Not Being Used

**Symptoms**: You've set `OPENAI_CODEX_API_KEY` but it's not being used.

**Expected Behavior**:
- OAuth authentication is always preferred
- API key is only injected when explicitly provided
- API key doesn't grant access to subscription-only models

**Solutions**:
1. **Verify OAuth is working**:
```bash
codex
# Check /about for auth status
```

2. **If you want to force API key usage**:
- This is not recommended with Codex CLI
- Consider using the standard `openai` provider instead

3. **Verify .env file is being loaded**:
```bash
# Check if .env exists in project root
ls -la .env

# Verify OPENAI_CODEX_API_KEY is set
grep OPENAI_CODEX_API_KEY .env
```

### Approval/Sandbox Issues

**Symptoms**: Commands are blocked or filesystem access is denied.

**Solutions**:

1. **Adjust approval mode**:
```json
{
"codexCli": {
"approvalMode": "on-request"
}
}
```

2. **Adjust sandbox mode**:
```json
{
"codexCli": {
"sandboxMode": "workspace-write"
}
}
```

3. **For fully automated workflows** (use cautiously):
```json
{
"codexCli": {
"fullAuto": true
}
}
```

## Important Notes

- **OAuth subscription required**: No API key needed for basic operation, but requires active ChatGPT subscription
- **Limited model selection**: Only `gpt-5` and `gpt-5-codex` available via OAuth
- **Pricing information**: Not available for OAuth models (shows as "Unknown" in cost calculations)
- **No automatic dependency**: The `@openai/codex` package is not added to Task Master's dependencies - install it globally or enable `allowNpx`
- **Codebase analysis**: Automatically enabled when using `codex-cli` provider
- **Safety first**: Default settings prioritize safety with `approvalMode: "on-failure"` and `sandboxMode: "workspace-write"`

## See Also

- [Configuration Guide](../configuration.md#codex-cli-provider) - Complete Codex CLI configuration reference
- [Command Reference](../command-reference.md) - Using `--codex-cli` flag with commands
- [Gemini CLI Provider](./gemini-cli.md) - Similar CLI-based provider for Google Gemini
- [Claude Code Integration](../claude-code-integration.md) - Another CLI-based provider
- [ai-sdk-provider-codex-cli](https://github.com/ben-vargas/ai-sdk-provider-codex-cli) - Source code for the provider package
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

LGTM! Excellent comprehensive Codex CLI provider documentation.

This documentation is thorough and well-structured, covering all essential aspects from quickstart to troubleshooting. The organization makes it easy for users to find information at different skill levels.

Optional: Fix markdown formatting for consistency.

Static analysis detected multiple instances of missing blank lines around fenced code blocks (MD031 violations at lines 92, 350, 355, 360, 374, 379, 385, 400, 405, 410, 412, 444, 454, 469, 478, 487). While these don't affect functionality, adding blank lines would improve markdown consistency:

 To verify your authentication:
+
 ```bash
 # Open interactive Codex CLI
 codex

Optional: API Key Method


Apply similar spacing around all code blocks for better consistency with markdown best practices.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>πŸͺ› markdownlint-cli2 (0.18.1)</summary>

92-92: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

350-350: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

355-355: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

360-360: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

374-374: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

379-379: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

385-385: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

400-400: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

405-405: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

410-410: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

412-412: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

444-444: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

454-454: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

469-469: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

478-478: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

487-487: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

</details>

</details>

<details>
<summary>πŸ€– Prompt for AI Agents</summary>

In docs/providers/codex-cli.md lines 1-510, static analysis flagged MD031
(missing blank lines around fenced code blocks) at several locations (e.g., ~92,
350, 355, 360, 374, 379, 385, 400, 405, 410, 412, 444, 454, 469, 478, 487); fix
by adding a blank line immediately before and after each fenced code block
(bash or json blocks) so every fenced block is separated from surrounding
text with one empty line, matching the example shown in the review and ensuring
consistent markdown formatting throughout the document.


</details>

<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines 429 to 434
model: client(params.modelId),
system: systemPrompt,
messages: messages,
maxTokens: params.maxTokens,
maxOutputTokens: params.maxTokens,
temperature: params.temperature
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Stop forwarding temperature when the provider says it cannot.

GeminiCliProvider sets supportsTemperature = false, yet this override always passes params.temperature through to the SDK (same issue in streamText and the generateObject retry path). Gemini CLI rejects a temperature argument, so any call that supplies one will fail even though the provider advertises that it doesn’t support it. Reuse the base-class guard (this.supportsTemperature && …) and stick with prepareTokenParam so you don’t leak unsupported knobs.

-			const result = await generateText({
-				model: client(params.modelId),
-				system: systemPrompt,
-				messages: messages,
-				maxOutputTokens: params.maxTokens,
-				temperature: params.temperature
-			});
+			const tokenParams = this.prepareTokenParam(
+				params.modelId,
+				params.maxTokens
+			);
+			const request = {
+				model: client(params.modelId),
+				system: systemPrompt,
+				messages,
+				...tokenParams,
+				...(this.supportsTemperature && params.temperature !== undefined
+					? { temperature: params.temperature }
+					: {})
+			};
+			const result = await generateText(request);

Apply the same guard/prepareTokenParam pattern to streamText (Line 533) and the manual generateObject retry (Line 590).

πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
model: client(params.modelId),
system: systemPrompt,
messages: messages,
maxTokens: params.maxTokens,
maxOutputTokens: params.maxTokens,
temperature: params.temperature
});
// replace the original generateText call with temperature guard + token params
const tokenParams = this.prepareTokenParam(
params.modelId,
params.maxTokens
);
const request = {
model: client(params.modelId),
system: systemPrompt,
messages,
...tokenParams,
...(this.supportsTemperature && params.temperature !== undefined
? { temperature: params.temperature }
: {})
};
const result = await generateText(request);
πŸ€– Prompt for AI Agents
In src/ai-providers/gemini-cli.js around lines 429-434, 533, and 590, stop
always forwarding params.temperature to the Gemini SDK; since GeminiCliProvider
sets supportsTemperature = false, wrap temperature in the base-class guard and
use the prepareTokenParam helper (e.g. set temperature only if
this.supportsTemperature && prepareTokenParam(params.temperature)), applying
that same pattern in the streamText call (line ~533) and the manual
generateObject retry path (line ~590) so unsupported temperature values are
never passed to the SDK.

…r not provided (#1276)

Co-authored-by: Ralph Khreish <[email protected]>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Fixes #1272
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

πŸ“œ Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 4b54738 and caee040.

πŸ“’ Files selected for processing (2)
  • .changeset/fix-mcp-default-tasks-path.md (1 hunks)
  • mcp-server/src/core/utils/path-utils.js (1 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (6)
.changeset/*.md

πŸ“„ CodeRabbit inference engine (.cursor/rules/changeset.mdc)

.changeset/*.md: When running npm run changeset or npx changeset add, provide a concise summary of the changes for the CHANGELOG.md in imperative mood, typically a single line, and not a detailed Git commit message.
The changeset summary should be user-facing, describing what changed in the released version that is relevant to users or consumers of the package.
Do not use your detailed Git commit message body as the changeset summary.

Files:

  • .changeset/fix-mcp-default-tasks-path.md
.changeset/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/new_features.mdc)

Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.

Files:

  • .changeset/fix-mcp-default-tasks-path.md
**/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

**/*.js: Declare and initialize global variables at the top of modules to avoid hoisting issues.
Use proper function declarations to avoid hoisting issues and initialize variables before they are referenced.
Do not reference variables before their declaration in module scope.
Use dynamic imports (import()) to avoid initialization order issues in modules.

Files:

  • mcp-server/src/core/utils/path-utils.js
mcp-server/src/{core/utils,tools}/**/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/utilities.mdc)

Place utilities specifically designed to support the MCP server implementation into the appropriate subdirectories within mcp-server/src/ (e.g., path/core logic helpers in mcp-server/src/core/utils/, tool execution/response helpers in mcp-server/src/tools/utils.js).

Files:

  • mcp-server/src/core/utils/path-utils.js
mcp-server/src/core/utils/path-utils.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/utilities.mdc)

Call findTasksJsonPath(args, log) from within direct function wrappers in mcp-server/src/core/direct-functions/ to get the absolute path to the relevant tasks.json.

Files:

  • mcp-server/src/core/utils/path-utils.js
{scripts/modules/utils.js,mcp-server/src/core/utils/path-utils.js,mcp-server/src/tools/utils.js}

πŸ“„ CodeRabbit inference engine (.cursor/rules/utilities.mdc)

{scripts/modules/utils.js,mcp-server/src/core/utils/path-utils.js,mcp-server/src/tools/utils.js}: Keep utilities relevant to their location, export all utility functions in a single statement per file, group related exports together, export configuration constants, do not use default exports, and do not create circular dependencies.
Export all utility functions explicitly, group related functions logically, and include new tagged system utilities.

Files:

  • mcp-server/src/core/utils/path-utils.js
🧠 Learnings (9)
πŸ““ Common learnings
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1262
File: scripts/modules/task-manager/update-tasks.js:216-233
Timestamp: 2025-10-01T19:53:34.261Z
Learning: For scripts/modules/task-manager/*.js: Use generateObjectService with Zod schemas for structured AI responses rather than generateTextService + manual JSON parsing, as modern AI providers increasingly support the tool use and generateObject paradigm with improved reliability.
πŸ“š Learning: 2025-09-24T15:12:58.855Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/AGENTS.md:0-0
Timestamp: 2025-09-24T15:12:58.855Z
Learning: Applies to assets/**/.mcp.json : Configure the Task Master MCP server in .mcp.json under mcpServers.task-master-ai using npx task-master-ai and provide required API key env vars

Applied to files:

  • .changeset/fix-mcp-default-tasks-path.md
πŸ“š Learning: 2025-07-17T21:33:57.585Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1002
File: .changeset/puny-friends-give.md:2-3
Timestamp: 2025-07-17T21:33:57.585Z
Learning: In the eyaltoledano/claude-task-master repository, the MCP server code in mcp-server/src/ is part of the main "task-master-ai" package, not a separate "mcp-server" package. When creating changesets for MCP server changes, use "task-master-ai" as the package name.

Applied to files:

  • .changeset/fix-mcp-default-tasks-path.md
πŸ“š Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to mcp-server/src/core/utils/path-utils.js : Call `findTasksJsonPath(args, log)` from within direct function wrappers in `mcp-server/src/core/direct-functions/` to get the absolute path to the relevant `tasks.json`.

Applied to files:

  • mcp-server/src/core/utils/path-utils.js
πŸ“š Learning: 2025-07-18T17:11:36.732Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-07-18T17:11:36.732Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : The *Direct function is responsible for finding the exact tasks.json path using findTasksJsonPath, relying on the projectRoot passed in args.

Applied to files:

  • mcp-server/src/core/utils/path-utils.js
πŸ“š Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to mcp-server/src/tools/utils.js : Use `normalizeProjectRoot(rawPath, log)`, `getRawProjectRootFromSession(session, log)`, and `withNormalizedProjectRoot(executeFn)` in `mcp-server/src/tools/utils.js` to ensure project root paths are normalized for MCP tools.

Applied to files:

  • mcp-server/src/core/utils/path-utils.js
πŸ“š Learning: 2025-07-18T05:38:17.352Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#943
File: scripts/modules/task-manager/move-task.js:24-24
Timestamp: 2025-07-18T05:38:17.352Z
Learning: In the Claude Task Master system, core task-manager functions are designed with fallback mechanisms for missing projectRoot parameters using the pattern `const projectRoot = providedProjectRoot || findProjectRoot();`. The readJSON and writeJSON functions have default parameters (projectRoot = null, tag = null) and handle missing parameters gracefully. Adding strict validation to these core functions would break the established flexible architecture pattern.

Applied to files:

  • mcp-server/src/core/utils/path-utils.js
πŸ“š Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Create direct function wrappers in 'mcp-server/src/core/direct-functions/' for MCP tool implementation, following silent mode patterns and using findTasksJsonPath for consistent path resolution.

Applied to files:

  • mcp-server/src/core/utils/path-utils.js
πŸ“š Learning: 2025-07-18T17:11:36.732Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-07-18T17:11:36.732Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Use path.join() instead of string concatenation for file paths, and follow established file naming conventions (e.g., 'task_001.txt') in direct functions.

Applied to files:

  • mcp-server/src/core/utils/path-utils.js
🧬 Code graph analysis (1)
mcp-server/src/core/utils/path-utils.js (1)
src/utils/path-utils.js (8)
  • defaultPath (343-343)
  • defaultPath (395-395)
  • projectRoot (108-108)
  • projectRoot (197-197)
  • projectRoot (269-269)
  • projectRoot (340-340)
  • projectRoot (386-386)
  • projectRoot (445-445)
πŸͺ› markdownlint-cli2 (0.18.1)
.changeset/fix-mcp-default-tasks-path.md

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


5-5: Files should end with a single newline character

(MD047, single-trailing-newline)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build
  • GitHub Check: typecheck
  • GitHub Check: Test
  • GitHub Check: Test
  • GitHub Check: update-docs
πŸ”‡ Additional comments (1)
mcp-server/src/core/utils/path-utils.js (1)

91-94: LGTM!

The refactoring to introduce the foundPath variable improves readability, and the explanatory comment clearly documents why no default path fallback is available in this branch.

"task-master-ai": patch
---

Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error. No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Add trailing newline.

The file should end with a single newline character to comply with standard formatting conventions.

Apply this diff to add the trailing newline:

-Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.
+Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.
+
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.
Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.
🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


5-5: Files should end with a single newline character

(MD047, single-trailing-newline)

πŸ€– Prompt for AI Agents
In .changeset/fix-mcp-default-tasks-path.md around line 5, the file is missing a
trailing newline; add a single newline character at the end of the file so it
ends with exactly one trailing newline to comply with standard file formatting.

Comment on lines +72 to +87
const foundPath = coreFindTasksPath(explicitPath, { projectRoot }, log);
// If core function returns null and no explicit path was provided,
// construct the expected default path as documented
if (foundPath === null && !explicitPath) {
const defaultPath = path.join(
projectRoot,
'.taskmaster',
'tasks',
'tasks.json'
);
log?.info?.(
`Core findTasksPath returned null, using default path: ${defaultPath}`
);
return defaultPath;
}
return foundPath;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Consider using a shared constant for the default path.

The hardcoded path construction '.taskmaster', 'tasks', 'tasks.json' duplicates logic that likely exists in a constant (e.g., TASKMASTER_TASKS_FILE as seen in src/utils/path-utils.js:342). Using a shared constant would improve maintainability and prevent drift between the MCP server and core utilities.

If a constant like TASKMASTER_TASKS_FILE exists, import and use it:

+import { TASKMASTER_TASKS_FILE } from '../../../../src/constants/paths.js';

...

-		const defaultPath = path.join(
-			projectRoot,
-			'.taskmaster',
-			'tasks',
-			'tasks.json'
-		);
+		const defaultPath = path.join(projectRoot, TASKMASTER_TASKS_FILE);
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const foundPath = coreFindTasksPath(explicitPath, { projectRoot }, log);
// If core function returns null and no explicit path was provided,
// construct the expected default path as documented
if (foundPath === null && !explicitPath) {
const defaultPath = path.join(
projectRoot,
'.taskmaster',
'tasks',
'tasks.json'
);
log?.info?.(
`Core findTasksPath returned null, using default path: ${defaultPath}`
);
return defaultPath;
}
return foundPath;
// ─── At the top of mcp-server/src/core/utils/path-utils.js ────────────────────────
import { TASKMASTER_TASKS_FILE } from '../../../../src/constants/paths.js';
…
const foundPath = coreFindTasksPath(explicitPath, { projectRoot }, log);
// If core function returns null and no explicit path was provided,
// construct the expected default path as documented
if (foundPath === null && !explicitPath) {
const defaultPath = path.join(projectRoot, TASKMASTER_TASKS_FILE);
log?.info?.(
`Core findTasksPath returned null, using default path: ${defaultPath}`
);
return defaultPath;
}
return foundPath;
πŸ€– Prompt for AI Agents
In mcp-server/src/core/utils/path-utils.js around lines 72 to 87, replace the
hardcoded default path construction ('.taskmaster', 'tasks', 'tasks.json') with
the shared TASKMASTER_TASKS_FILE constant to avoid duplication; import
TASKMASTER_TASKS_FILE from its module (e.g., '../../utils/path-utils' or the
correct relative path where it is defined) at the top of this file and use
path.join(projectRoot, TASKMASTER_TASKS_FILE) (or simply
path.resolve(projectRoot, TASKMASTER_TASKS_FILE) if appropriate), and update the
log message to reference the constant-based path instead of the hardcoded
segments.

Co-authored-by: Ralph Khreish <[email protected]>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Resolves issue #1271 - MCP Connection Closed Error After Upgrading to v0.27.3
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
scripts/modules/task-manager/add-subtask.js (1)

21-21: Remove the unused generateFiles parameter.

The generateFiles parameter is no longer used since task file generation has been removed. Consider removing this parameter to clean up the function signature and avoid confusion for callers.

Apply this diff to remove the unused parameter:

 async function addSubtask(
 	tasksPath,
 	parentId,
 	existingTaskId = null,
 	newSubtaskData = null,
-	generateFiles = false,
 	context = {}
 )

Note: If this is a public API and you need to maintain backward compatibility, you could deprecate the parameter in documentation instead of removing it immediately.

scripts/modules/task-manager/remove-subtask.js (1)

18-18: Remove the unused generateFiles parameter.

The generateFiles parameter is no longer used since task file generation has been removed. Consider removing this parameter to clean up the function signature.

Apply this diff to remove the unused parameter:

 async function removeSubtask(
 	tasksPath,
 	subtaskId,
 	convertToTask = false,
-	generateFiles = false,
 	context = {}
 )

Note: If backward compatibility is a concern, deprecate in documentation first.

scripts/modules/task-manager/move-task.js (1)

115-115: Remove the unused generateFiles parameter.

The generateFiles parameter is no longer used since task file generation has been removed. Even though the recursive call at line 138 explicitly passes false for this parameter, it serves no purpose and should be removed for clarity.

Apply this diff to remove the unused parameter:

 async function moveTask(
 	tasksPath,
 	sourceId,
 	destinationId,
-	generateFiles = false,
 	options = {}
 )

And update the recursive call at line 138:

 			const result = await moveTask(
 				tasksPath,
 				sourceIds[i],
 				destinationIds[i],
-				false, // Don't generate files for each individual move
 				options
 			);

Note: If this is a public API requiring backward compatibility, consider deprecating first.

πŸ“œ Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between caee040 and 7b5a7c4.

πŸ“’ Files selected for processing (6)
  • .changeset/fix-mcp-connection-errors.md (1 hunks)
  • scripts/modules/task-manager/add-subtask.js (1 hunks)
  • scripts/modules/task-manager/move-task.js (2 hunks)
  • scripts/modules/task-manager/remove-subtask.js (1 hunks)
  • tests/unit/scripts/modules/task-manager/add-subtask.test.js (0 hunks)
  • tests/unit/scripts/modules/task-manager/move-task.test.js (0 hunks)
πŸ’€ Files with no reviewable changes (2)
  • tests/unit/scripts/modules/task-manager/move-task.test.js
  • tests/unit/scripts/modules/task-manager/add-subtask.test.js
🧰 Additional context used
πŸ““ Path-based instructions (7)
scripts/modules/task-manager/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_services.mdc)

scripts/modules/task-manager/*.js: Centralize all LLM calls through generateTextService or generateObjectService.
Do not import or call anything from the old ai-services.js, ai-client-factory.js, or ai-client-utils.js files.
Do not initialize AI clients (Anthropic, Perplexity, etc.) directly within core logic (task-manager/) or MCP direct functions.
Do not fetch AI-specific parameters (model ID, max tokens, temp) using config-manager.js getters for the AI call. Pass the role instead.
Do not implement fallback or retry logic outside ai-services-unified.js.
Do not handle API key resolution outside the service layer (it uses utils.js internally).
Determine the appropriate role (main, research, fallback) in your core logic and pass it to the service.
Pass the session object (received in the context parameter, especially from direct function wrappers) to the service call when in MCP context.
Use generateTextService and implement robust manual JSON parsing (with Zod validation after parsing) when structured output is needed, as generateObjectService has shown unreliability with some providers/schemas.
Be aware of potential reliability issues with generateObjectService across different providers and complex schemas. Prefer generateTextService + manual parsing as a more robust alternative for structured data needs.

Files in scripts/modules/task-manager/ should each handle a specific action related to task management (e.g., add-task.js, expand-task.js), supporting the tagged task lists system and backward compatibility.

Files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
scripts/modules/**

πŸ“„ CodeRabbit inference engine (.cursor/rules/dev_workflow.mdc)

When using the MCP server, restart it if core logic in scripts/modules or MCP tool/direct function definitions change.

Files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
scripts/modules/task-manager/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/tags.mdc)

scripts/modules/task-manager/*: All core functions in scripts/modules/task-manager/ must accept a context parameter and use it to extract projectRoot and tag
All core functions in scripts/modules/task-manager/ must use readJSON(tasksPath, projectRoot, tag) and writeJSON(tasksPath, data, projectRoot, tag)

Files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
scripts/modules/task-manager/**/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/telemetry.mdc)

scripts/modules/task-manager/**/*.js: Functions in scripts/modules/task-manager/ that invoke AI services must call the appropriate AI service function (e.g., generateObjectService), passing commandName and outputType in the params object.
Core logic functions in scripts/modules/task-manager/ must return an object that includes aiServiceResponse.telemetryData.
If the core logic function handles CLI output (outputFormat === 'text' or 'cli'), and aiServiceResponse.telemetryData is available, it must call displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli') from scripts/modules/ui.js.

Do not call AI-specific getters (like getMainModelId, getMainMaxTokens) from core logic functions in scripts/modules/task-manager/*; instead, pass the role to the unified AI service.

Files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
**/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

**/*.js: Declare and initialize global variables at the top of modules to avoid hoisting issues.
Use proper function declarations to avoid hoisting issues and initialize variables before they are referenced.
Do not reference variables before their declaration in module scope.
Use dynamic imports (import()) to avoid initialization order issues in modules.

Files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
.changeset/*.md

πŸ“„ CodeRabbit inference engine (.cursor/rules/changeset.mdc)

.changeset/*.md: When running npm run changeset or npx changeset add, provide a concise summary of the changes for the CHANGELOG.md in imperative mood, typically a single line, and not a detailed Git commit message.
The changeset summary should be user-facing, describing what changed in the released version that is relevant to users or consumers of the package.
Do not use your detailed Git commit message body as the changeset summary.

Files:

  • .changeset/fix-mcp-connection-errors.md
.changeset/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/new_features.mdc)

Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.

Files:

  • .changeset/fix-mcp-connection-errors.md
🧠 Learnings (24)
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use AI to generate detailed subtasks within the current tag context, considering complexity analysis for subtask counts and ensuring proper IDs for newly created subtasks.

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-31T22:07:49.716Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-31T22:07:49.716Z
Learning: Applies to scripts/modules/commands.js : Follow the provided structure for removing subtasks, including options for conversion, file path, and regeneration, with detailed error handling.

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use consistent formatting for task files, include all task properties in text files, and format dependencies with status indicators.

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Do not create circular dependencies between subtasks

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Generate task files from the current tag context, include tag information in generated files, and do not mix tasks from different tags in file generation.

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Provide functions for updating task status within the current tag context, handling both individual tasks and subtasks, and considering subtask status when updating parent tasks.

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
πŸ“š Learning: 2025-07-18T17:07:39.336Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-07-18T17:07:39.336Z
Learning: Applies to scripts/modules/task-manager/*.js : Files in scripts/modules/task-manager/ should each handle a specific action related to task management (e.g., add-task.js, expand-task.js), supporting the tagged task lists system and backward compatibility.

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Allow numeric subtask IDs to reference other subtasks within the same parent

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
πŸ“š Learning: 2025-07-18T17:08:48.695Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-18T17:08:48.695Z
Learning: Applies to scripts/modules/commands.js : Follow the provided structure for adding subtasks, including required options and detailed error handling.

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
πŸ“š Learning: 2025-09-24T15:12:12.658Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/.windsurfrules:0-0
Timestamp: 2025-09-24T15:12:12.658Z
Learning: Use task-master generate to create or update task files from tasks.json and keep dependencies valid with fix-dependencies

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-31T22:07:49.716Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-31T22:07:49.716Z
Learning: Applies to scripts/modules/commands.js : Follow the provided structure for adding subtasks, including required and optional options, parameter validation, and detailed error handling.

Applied to files:

  • scripts/modules/task-manager/add-subtask.js
πŸ“š Learning: 2025-07-18T17:06:57.833Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-07-18T17:06:57.833Z
Learning: Applies to scripts/modules/task-manager/*.js : Do not import or call anything from the old `ai-services.js`, `ai-client-factory.js`, or `ai-client-utils.js` files.

Applied to files:

  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Check for and remove references to non-existent tasks during cleanup

Applied to files:

  • scripts/modules/task-manager/remove-subtask.js
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Remove references to non-existent tasks during validation

Applied to files:

  • scripts/modules/task-manager/remove-subtask.js
πŸ“š Learning: 2025-07-18T17:08:48.695Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-18T17:08:48.695Z
Learning: Applies to scripts/modules/commands.js : Follow the provided structure for removing subtasks, including required options, conversion option, and detailed error handling.

Applied to files:

  • scripts/modules/task-manager/remove-subtask.js
πŸ“š Learning: 2025-07-18T17:13:30.188Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tags.mdc:0-0
Timestamp: 2025-07-18T17:13:30.188Z
Learning: Applies to scripts/modules/task-manager/* : All core functions in scripts/modules/task-manager/ must use readJSON(tasksPath, projectRoot, tag) and writeJSON(tasksPath, data, projectRoot, tag)

Applied to files:

  • scripts/modules/task-manager/remove-subtask.js
  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-09-24T15:12:58.855Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/AGENTS.md:0-0
Timestamp: 2025-09-24T15:12:58.855Z
Learning: Applies to assets/**/.mcp.json : Configure the Task Master MCP server in .mcp.json under mcpServers.task-master-ai using npx task-master-ai and provide required API key env vars

Applied to files:

  • .changeset/fix-mcp-connection-errors.md
πŸ“š Learning: 2025-07-17T21:33:57.585Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1002
File: .changeset/puny-friends-give.md:2-3
Timestamp: 2025-07-17T21:33:57.585Z
Learning: In the eyaltoledano/claude-task-master repository, the MCP server code in mcp-server/src/ is part of the main "task-master-ai" package, not a separate "mcp-server" package. When creating changesets for MCP server changes, use "task-master-ai" as the package name.

Applied to files:

  • .changeset/fix-mcp-connection-errors.md
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Implement silent migration from legacy to tagged format in the readJSON() function, detect legacy format, convert automatically, and preserve all existing task data during migration.

Applied to files:

  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/task-manager.js : Features that create, read, update, or delete tasks belong in 'scripts/modules/task-manager.js'.

Applied to files:

  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to scripts/modules/utils.js : Use tagged task system aware functions for task finding and manipulation, handle both task and subtask operations, and validate task IDs before operations.

Applied to files:

  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to scripts/modules/utils.js : Use tag resolution functions for all task data access, provide backward compatibility with legacy format, and default to 'master' tag when no tag is specified.

Applied to files:

  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Represent task dependencies as arrays of task IDs

Applied to files:

  • scripts/modules/task-manager/move-task.js
πŸ“š Learning: 2025-07-18T17:10:12.881Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:12.881Z
Learning: Applies to tasks.json : Use the `tasks.json` file (generated by Taskmaster) to store the project's task list, including tags and task structures.

Applied to files:

  • scripts/modules/task-manager/move-task.js
πŸͺ› markdownlint-cli2 (0.18.1)
.changeset/fix-mcp-connection-errors.md

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


5-5: Files should end with a single newline character

(MD047, single-trailing-newline)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: typecheck
  • GitHub Check: build
  • GitHub Check: Test
  • GitHub Check: Test
  • GitHub Check: update-docs
πŸ”‡ Additional comments (3)
scripts/modules/task-manager/add-subtask.js (1)

142-142: LGTM! Clear documentation of the removed feature.

The inline note effectively documents the removal of task file generation functionality.

scripts/modules/task-manager/remove-subtask.js (1)

109-109: LGTM! Clear documentation of the removed feature.

The inline note effectively documents the removal of task file generation functionality.

scripts/modules/task-manager/move-task.js (1)

144-144: LGTM! Clear documentation of the removed feature.

The inline notes at both the batch move path (line 144) and single move path (line 205) effectively document the removal of task file generation functionality.

Also applies to: 205-205

"task-master-ai": patch
---

Fix MCP connection errors caused by deprecated generateTaskFiles calls. Resolves "Cannot read properties of null (reading 'toString')" errors when using MCP tools for task management operations. No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Add the trailing newline.

The file is missing the terminal newline, which triggers markdownlint MD047. Please append a newline at EOF so the changeset passes lint.

🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


5-5: Files should end with a single newline character

(MD047, single-trailing-newline)

πŸ€– Prompt for AI Agents
In .changeset/fix-mcp-connection-errors.md around line 5, the file is missing a
terminal newline which triggers markdownlint MD047; open the file and append a
single trailing newline (ensure the file ends with '\n') so the changeset passes
lint.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
packages/tm-core/src/types/index.ts (1)

172-185: isTaskStatus omits 'completed' from TaskStatus union.

Tasks with status 'completed' will fail the guard.

Apply this diff:

 export function isTaskStatus(value: unknown): value is TaskStatus {
   return (
     typeof value === 'string' &&
-    [
+    [
       'pending',
       'in-progress',
       'done',
       'deferred',
       'cancelled',
       'blocked',
-      'review'
+      'review',
+      'completed'
     ].includes(value)
   );
 }
packages/tm-core/src/entities/task.entity.ts (1)

122-132: Status validator omits 'completed'.

This rejects valid tasks if 'completed' is used.

Apply this diff:

 private isValidStatus(status: any): status is TaskStatus {
   return [
     'pending',
     'in-progress',
     'done',
     'deferred',
     'cancelled',
     'blocked',
-    'review'
+    'review',
+    'completed'
   ].includes(status);
 }
packages/tm-core/src/mappers/TaskMapper.ts (1)

142-144: Null-safe subtask sorting.

If subtask_position is null/undefined, subtraction yields NaN.

Apply this diff:

-      subtasks.sort((a, b) => a.subtask_position - b.subtask_position);
+      subtasks.sort((a, b) => {
+        const aPos = a.subtask_position ?? Number.MAX_SAFE_INTEGER;
+        const bPos = b.subtask_position ?? Number.MAX_SAFE_INTEGER;
+        return aPos - bPos;
+      });
packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (2)

13-22: Fix status schema vs DB mapping mismatch (runtime error risk).

Zod allows statuses (review, deferred, cancelled, blocked) that mapStatusToDatabase cannot handle; parse succeeds then mapping throws. Align schema with supported statuses.

Apply this diff to restrict allowed statuses:

-// Zod schema for task status validation
-const TaskStatusSchema = z.enum([
-  'pending',
-  'in-progress',
-  'done',
-  'review',
-  'deferred',
-  'cancelled',
-  'blocked'
-]);
+// Zod schema for task status validation (must match mapStatusToDatabase)
+const TaskStatusSchema = z.enum(['pending', 'in-progress', 'done']);

Alternative (if you need the extra states): extend mapStatusToDatabase to coerce them to 'todo' | 'in_progress' appropriately; otherwise reject them at validation time as above.

Also applies to: 218-233


24-35: Remove redundant .partial().

Fields are already optional; .partial() is unnecessary and may confuse readers.

Apply this diff:

-const TaskUpdateSchema = z
-  .object({
+const TaskUpdateSchema = z.object({
     title: z.string().min(1).optional(),
     description: z.string().optional(),
     status: TaskStatusSchema.optional(),
     priority: z.enum(['low', 'medium', 'high', 'critical']).optional(),
     details: z.string().optional(),
     testStrategy: z.string().optional()
-  })
-  .partial();
+});
πŸ“œ Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 7b5a7c4 and db6f405.

β›” Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
πŸ“’ Files selected for processing (13)
  • apps/cli/src/commands/list.command.ts (4 hunks)
  • apps/cli/src/commands/set-status.command.ts (0 hunks)
  • apps/cli/src/ui/components/task-detail.component.ts (5 hunks)
  • apps/cli/src/utils/ui.ts (5 hunks)
  • packages/tm-core/src/entities/task.entity.ts (4 hunks)
  • packages/tm-core/src/mappers/TaskMapper.test.ts (1 hunks)
  • packages/tm-core/src/mappers/TaskMapper.ts (5 hunks)
  • packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1 hunks)
  • packages/tm-core/src/repositories/supabase/index.ts (1 hunks)
  • packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (7 hunks)
  • packages/tm-core/src/storage/api-storage.ts (1 hunks)
  • packages/tm-core/src/types/index.ts (1 hunks)
  • packages/tm-core/src/types/repository-types.ts (1 hunks)
πŸ’€ Files with no reviewable changes (1)
  • apps/cli/src/commands/set-status.command.ts
🧰 Additional context used
πŸ““ Path-based instructions (4)
**/*.{test,spec}.{js,ts,jsx,tsx}

πŸ“„ CodeRabbit inference engine (.cursor/rules/git_workflow.mdc)

**/*.{test,spec}.{js,ts,jsx,tsx}: Create a test file and ensure all tests pass when all subtasks are complete; commit tests if added or modified
When all subtasks are complete, run final testing using the appropriate test runner (e.g., npm test, jest, or manual testing)

Files:

  • packages/tm-core/src/mappers/TaskMapper.test.ts
**/*.{test,spec}.*

πŸ“„ CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

Test files should follow naming conventions: .test., .spec., or _test. depending on the language

Files:

  • packages/tm-core/src/mappers/TaskMapper.test.ts
**/?(*.)+(spec|test).ts

πŸ“„ CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

In JavaScript/TypeScript projects using Jest, test files should match *.test.ts and *.spec.ts patterns

Files:

  • packages/tm-core/src/mappers/TaskMapper.test.ts
**/*.test.ts

πŸ“„ CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

**/*.test.ts: Use established mocking patterns for dependencies such as bcrypt and Prisma in test files
Test all code paths, including edge cases and error scenarios, in test files
Use descriptive names for test functions, such as should_return_error_for_invalid_input

Files:

  • packages/tm-core/src/mappers/TaskMapper.test.ts
🧠 Learnings (11)
πŸ““ Common learnings
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1262
File: scripts/modules/task-manager/update-tasks.js:216-233
Timestamp: 2025-10-01T19:53:34.261Z
Learning: For scripts/modules/task-manager/*.js: Use generateObjectService with Zod schemas for structured AI responses rather than generateTextService + manual JSON parsing, as modern AI providers increasingly support the tool use and generateObject paradigm with improved reliability.
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Represent task dependencies as arrays of task IDs

Applied to files:

  • packages/tm-core/src/mappers/TaskMapper.ts
  • apps/cli/src/ui/components/task-detail.component.ts
  • packages/tm-core/src/repositories/supabase/dependency-fetcher.ts
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Format task and dependency IDs consistently when adding dependencies

Applied to files:

  • packages/tm-core/src/mappers/TaskMapper.ts
  • apps/cli/src/ui/components/task-detail.component.ts
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Support both task and subtask dependencies in cycle detection

Applied to files:

  • packages/tm-core/src/mappers/TaskMapper.ts
  • apps/cli/src/ui/components/task-detail.component.ts
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Allow numeric subtask IDs to reference other subtasks within the same parent

Applied to files:

  • packages/tm-core/src/entities/task.entity.ts
  • apps/cli/src/ui/components/task-detail.component.ts
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Subtasks must use consistent properties, maintain simple numeric IDs unique within the parent task, and must not duplicate parent task properties.

Applied to files:

  • packages/tm-core/src/entities/task.entity.ts
πŸ“š Learning: 2025-09-26T19:05:47.555Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: packages/ai-sdk-provider-grok-cli/package.json:11-13
Timestamp: 2025-09-26T19:05:47.555Z
Learning: In the eyaltoledano/claude-task-master repository, internal tm/ packages use a specific export pattern where the "exports" field points to TypeScript source files (./src/index.ts) while "main" points to compiled output (./dist/index.js) and "types" points to source files (./src/index.ts). This pattern is used consistently across internal packages like tm/core and tm/ai-sdk-provider-grok-cli because they are consumed directly during build-time bundling with tsdown rather than being published as separate packages.

Applied to files:

  • packages/tm-core/src/repositories/supabase/index.ts
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use consistent formatting for task files, include all task properties in text files, and format dependencies with status indicators.

Applied to files:

  • apps/cli/src/ui/components/task-detail.component.ts
πŸ“š Learning: 2025-07-18T17:09:40.548Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:40.548Z
Learning: Applies to scripts/modules/dependency-manager.js : Use string IDs with dot notation (e.g., "1.2") for subtask references

Applied to files:

  • apps/cli/src/ui/components/task-detail.component.ts
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Allow filtering tasks by status within the current tag context, handle subtask display in lists, and use consistent table formats.

Applied to files:

  • apps/cli/src/ui/components/task-detail.component.ts
πŸ“š Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to tests/{unit,integration,e2e}/**/*.test.js : Use sample task fixtures for consistent test data, mock file system operations, and test both success and error paths for task operations.

Applied to files:

  • packages/tm-core/src/mappers/TaskMapper.test.ts
🧬 Code graph analysis (7)
packages/tm-core/src/types/repository-types.ts (2)
packages/tm-core/src/types/database.types.ts (2)
  • Tables (413-436)
  • Database (9-411)
packages/tm-core/src/types/index.ts (1)
  • TaskMetadata (97-105)
apps/cli/src/commands/list.command.ts (1)
apps/cli/src/ui/components/next-task.component.ts (2)
  • getTaskDescription (125-141)
  • displayRecommendedNextTask (27-120)
packages/tm-core/src/mappers/TaskMapper.ts (2)
packages/tm-core/src/types/database.types.ts (1)
  • Tables (413-436)
packages/tm-core/src/types/index.ts (1)
  • Task (57-82)
apps/cli/src/ui/components/task-detail.component.ts (1)
apps/cli/src/utils/ui.ts (1)
  • getComplexityWithColor (105-115)
packages/tm-core/src/mappers/TaskMapper.test.ts (2)
packages/tm-core/src/types/database.types.ts (1)
  • Tables (413-436)
packages/tm-core/src/mappers/TaskMapper.ts (1)
  • TaskMapper (12-216)
packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1)
packages/tm-core/src/types/repository-types.ts (1)
  • DependencyWithDisplayId (21-26)
packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (4)
packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1)
  • DependencyFetcher (8-68)
packages/tm-core/src/types/database.types.ts (2)
  • Database (9-411)
  • Json (1-7)
packages/tm-core/src/types/repository-types.ts (2)
  • TaskWithRelations (9-16)
  • TaskDatabaseUpdate (40-41)
packages/tm-core/src/mappers/TaskMapper.ts (1)
  • TaskMapper (12-216)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test
  • GitHub Check: build
  • GitHub Check: typecheck
  • GitHub Check: Test
  • GitHub Check: update-docs
πŸ”‡ Additional comments (24)
packages/tm-core/src/types/repository-types.ts (9)

1-4: LGTM!

File header and imports are correctly structured. The .js extension in the import path is appropriate for ESM compatibility.


9-16: LGTM!

The TaskWithRelations interface appropriately extends the base tasks table row with an optional joined document relation. The structure aligns with typical SQL join patterns and provides type safety for related document data.


21-26: LGTM!

The DependencyWithDisplayId interface correctly models the dependency relationship with a nested display_id field, matching the expected join structure for task dependencies.


40-41: LGTM!

The TaskDatabaseUpdate type alias provides a convenient shorthand for the database update payload, improving code readability and maintainability.


45-50: LGTM!

The TaskQueryConfig interface provides clear configuration options for task queries with appropriate optional flags for including related data.


55-59: LGTM!

The TaskFetchResult interface appropriately aggregates task fetch results including the main task, subtasks, and a map of dependencies. The use of Map<string, string[]> for dependencies is a good choice for efficient lookups.


64-73: LGTM!

The TaskValidationError custom error class is well-structured with appropriate readonly properties for field and value, enabling detailed error context. The name property is correctly set for proper error identification.


78-83: LGTM!

The ContextValidationError custom error class is appropriately simple and follows error handling best practices by setting the name property correctly.


31-35: No TS conflict: separate TaskMetadata definitions
These interfaces live in different modules (types/index.ts vs. types/repository-types.ts) and are only imported via their distinct paths, so TypeScript won’t merge or collide them.

Likely an incorrect or invalid review comment.

apps/cli/src/utils/ui.ts (3)

87-100: LGTM!

The complexity level mapping logic is clear and well-structured. The thresholds (β‰₯7 for High, β‰₯4 for Medium, <4 for Low) are reasonable for a 0-10 scale, and the color choices (red, orange, green) provide intuitive visual feedback.


105-115: LGTM!

The updated implementation correctly handles both numeric and string inputs, provides appropriate fallback for invalid values, and uses the new getComplexityLevel helper for consistent color coding.


120-127: LGTM!

The new exported function provides a clear, formatted complexity display with score and label. The type guard correctly handles undefined input, and the output format (${complexity}/10 (${label})) is informative and user-friendly.

apps/cli/src/ui/components/task-detail.component.ts (3)

12-16: LGTM!

The import statement correctly adds getComplexityWithColor from the UI utilities module, which is needed for the complexity rendering changes below.


115-117: LGTM!

The complexity rendering correctly uses type guards and the new getComplexityWithColor helper, with an appropriate N/A fallback for missing or invalid complexity values.


331-331: LGTM!

The displaySubtasks call correctly aligns with the updated function signature, removing the parentId argument as expected.

apps/cli/src/commands/list.command.ts (3)

249-249: LGTM!

The subtask ID formatting change aligns with the simplification in task-detail.component.ts (line 230). This suggests that subtask.id now contains the full identifier rather than just the numeric part.


284-289: LGTM!

The separation of next task identification (nextTaskInfo) from full task lookup (nextTask) is a sound design that allows accessing enriched task data (including complexity) from storage while maintaining the existing recommendation logic.


311-321: LGTM!

The change from spreading nextTask to explicitly passing individual fields improves maintainability and type safety by:

  1. Making the interface contract explicit
  2. Preventing unintended property propagation
  3. Allowing proper type handling for complexity as number | undefined
packages/tm-core/src/types/index.ts (1)

76-81: LGTM on new complexity fields.

Shape and docs look good.

packages/tm-core/src/entities/task.entity.ts (2)

36-39: New complexity-related fields wired through entity/JSON: LGTM.

Also applies to: 68-71, 255-258


166-183: Confirm canonical final status: 'done' vs 'completed'.

markAsComplete sets 'done' while TaskStatus also includes 'completed'. Align on one to avoid ambiguity.

Would you like me to refactor to use 'completed' consistently across types/guards and mappers?

packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1)

16-38: Dependency fetch with joined display_ids: LGTM.

Input validation, error handling, and mapping are clean.

Please confirm the FK alias matches your generated types ('task_dependencies_depends_on_task_id_fkey') in the target DB.

packages/tm-core/src/repositories/supabase/index.ts (1)

1-5: Barrel exports LGTM.

Consolidating Supabase exports here improves DX and import consistency. Based on learnings.

packages/tm-core/src/storage/api-storage.ts (1)

19-19: Approve barrel import: no direct imports remain

No direct imports of supabase-task-repository.js found; all usage via barrel index.js.


subtasks.forEach((subtask) => {
const subtaskId = `${parentId}.${subtask.id}`;
const subtaskId = String(subtask.id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

🧩 Analysis chain

Verify subtask ID format consistency across the codebase.

The subtask ID construction was simplified from parentId.subtask.id to String(subtask.id). Ensure that:

  1. All subtask creation/storage logic populates subtask.id with the full ID (e.g., "1.2") rather than just the numeric part
  2. This change aligns with the subtask ID formatting in list.command.ts (line 249)

Run the following script to verify subtask ID handling:


🏁 Script executed:

#!/bin/bash
# Description: Verify subtask ID format usage across the codebase

# Search for subtask ID assignments and formatting
echo "=== Subtask ID assignments ==="
rg -nP -A3 -B3 'subtask\.id\s*=' --type=ts

echo -e "\n=== Subtask ID string concatenations (old pattern) ==="
rg -nP 'parentId.*subtask\.id|task\.id.*subtask\.id' --type=ts

echo -e "\n=== displaySubtasks calls ==="
rg -nP 'displaySubtasks\(' --type=ts -A2

Length of output: 2257


In apps/cli/src/ui/components/task-detail.component.ts:230, reinstate full dotted subtask IDs: String(subtask.id) only yields the numeric portion; prepend the parent task ID (e.g., ${task.id}.${subtask.id}) or ensure subtask.id carries the complete β€œ1.2” format.

πŸ€– Prompt for AI Agents
In apps/cli/src/ui/components/task-detail.component.ts around line 230,
converting subtask.id with String(subtask.id) strips the parent task prefix and
yields only the numeric part; restore full dotted IDs by using the composite
form (e.g., `${task.id}.${subtask.id}`) or ensure you read a preformatted dotted
id from the subtask object and use that instead; update the assignment to
produce the dotted id so downstream code displays and references the full "1.2"
style identifier.

Comment on lines +380 to 385
const complexityDisplay =
typeof subtask.complexity === 'number'
? getComplexityWithColor(subtask.complexity)
: '--';
subRow.push(chalk.gray(complexityDisplay));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Consider consistent fallback values.

Tasks use chalk.gray('N/A') for missing complexity (line 353), while subtasks use '--' (line 383). For consistency, consider using the same fallback value across both contexts.

Apply this diff to align the fallback values:

 				if (showComplexity) {
 					const complexityDisplay =
 						typeof subtask.complexity === 'number'
 							? getComplexityWithColor(subtask.complexity)
-							: '--';
+							: 'N/A';
 					subRow.push(chalk.gray(complexityDisplay));
 				}
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const complexityDisplay =
typeof subtask.complexity === 'number'
? getComplexityWithColor(subtask.complexity)
: '--';
subRow.push(chalk.gray(complexityDisplay));
}
if (showComplexity) {
const complexityDisplay =
typeof subtask.complexity === 'number'
? getComplexityWithColor(subtask.complexity)
: 'N/A';
subRow.push(chalk.gray(complexityDisplay));
}
πŸ€– Prompt for AI Agents
In apps/cli/src/utils/ui.ts around lines 380 to 385, the subtask complexity
fallback uses '--' while tasks use 'N/A'; change the subtask fallback string
from '--' to 'N/A' so both branches use the same fallback value (the existing
chalk.gray wrapping remains unchanged).

Comment on lines 54 to 58
this.subtasks = (data.subtasks || []).map((subtask) => ({
...subtask,
id: Number(subtask.id), // Keep subtask IDs as numbers per interface
id: String(subtask.id),
parentId: String(subtask.parentId)
}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inconsistent subtask ID types within TaskEntity (constructor normalizes to string; addSubtask uses number).

Mixed types can break equality/join logic and downstream assumptions.

Unify on string IDs to match constructor:

   addSubtask(subtask: Omit<Subtask, 'id' | 'parentId'>): void {
-    const nextId = this.subtasks.length + 1;
-    this.subtasks.push({
+    const nextId = String(this.subtasks.length + 1);
+    this.subtasks.push({
       ...subtask,
       id: nextId,
       parentId: this.id
     });
     this.updatedAt = new Date().toISOString();
   }

Also applies to: 202-209

πŸ€– Prompt for AI Agents
In packages/tm-core/src/entities/task.entity.ts around lines 54-58 (and also
update the addSubtask area at lines ~202-209), the constructor normalizes
subtask.id and subtask.parentId to strings but addSubtask currently creates
subtasks with numeric IDs; change addSubtask to convert id and parentId to
String(...) before storing (and ensure any new subtask objects follow the same
{...subtask, id: String(subtask.id), parentId: String(subtask.parentId)}
pattern) so all subtask IDs are consistently strings across the entity.

Comment on lines +7 to +148
describe('TaskMapper', () => {
describe('extractMetadataField', () => {
it('should extract string field from metadata', () => {
const taskRow: TaskRow = {
id: '123',
display_id: '1',
title: 'Test Task',
description: 'Test description',
status: 'todo',
priority: 'medium',
parent_task_id: null,
subtask_position: 0,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
metadata: {
details: 'Some details',
testStrategy: 'Test with unit tests'
},
complexity: null,
assignee_id: null,
estimated_hours: null,
actual_hours: null,
due_date: null,
completed_at: null
};

const task = TaskMapper.mapDatabaseTaskToTask(taskRow, [], new Map());

expect(task.details).toBe('Some details');
expect(task.testStrategy).toBe('Test with unit tests');
});

it('should use default value when metadata field is missing', () => {
const taskRow: TaskRow = {
id: '123',
display_id: '1',
title: 'Test Task',
description: 'Test description',
status: 'todo',
priority: 'medium',
parent_task_id: null,
subtask_position: 0,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
metadata: {},
complexity: null,
assignee_id: null,
estimated_hours: null,
actual_hours: null,
due_date: null,
completed_at: null
};

const task = TaskMapper.mapDatabaseTaskToTask(taskRow, [], new Map());

expect(task.details).toBe('');
expect(task.testStrategy).toBe('');
});

it('should use default value when metadata is null', () => {
const taskRow: TaskRow = {
id: '123',
display_id: '1',
title: 'Test Task',
description: 'Test description',
status: 'todo',
priority: 'medium',
parent_task_id: null,
subtask_position: 0,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
metadata: null,
complexity: null,
assignee_id: null,
estimated_hours: null,
actual_hours: null,
due_date: null,
completed_at: null
};

const task = TaskMapper.mapDatabaseTaskToTask(taskRow, [], new Map());

expect(task.details).toBe('');
expect(task.testStrategy).toBe('');
});

it('should use default value and warn when metadata field has wrong type', () => {
const consoleWarnSpy = vi
.spyOn(console, 'warn')
.mockImplementation(() => {});

const taskRow: TaskRow = {
id: '123',
display_id: '1',
title: 'Test Task',
description: 'Test description',
status: 'todo',
priority: 'medium',
parent_task_id: null,
subtask_position: 0,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
metadata: {
details: 12345, // Wrong type: number instead of string
testStrategy: ['test1', 'test2'] // Wrong type: array instead of string
},
complexity: null,
assignee_id: null,
estimated_hours: null,
actual_hours: null,
due_date: null,
completed_at: null
};

const task = TaskMapper.mapDatabaseTaskToTask(taskRow, [], new Map());

// Should use empty string defaults when type doesn't match
expect(task.details).toBe('');
expect(task.testStrategy).toBe('');

// Should have logged warnings
expect(consoleWarnSpy).toHaveBeenCalledWith(
expect.stringContaining('Type mismatch in metadata field "details"')
);
expect(consoleWarnSpy).toHaveBeenCalledWith(
expect.stringContaining(
'Type mismatch in metadata field "testStrategy"'
)
);

consoleWarnSpy.mockRestore();
});
});

describe('mapStatus', () => {
it('should map database status to internal status', () => {
expect(TaskMapper.mapStatus('todo')).toBe('pending');
expect(TaskMapper.mapStatus('in_progress')).toBe('in-progress');
expect(TaskMapper.mapStatus('done')).toBe('done');
});
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Unit tests look solid for metadata and status mapping.

Consider adding a parentId mapping assertion to prevent regressions.

Example additional test:

@@
 describe('TaskMapper', () => {
+  it('should set subtask.parentId to the exposed parent id (display_id when present)', () => {
+    const parent: TaskRow = {
+      id: 'uuid-123',
+      display_id: 'T-1',
+      title: 'Parent',
+      description: '',
+      status: 'todo',
+      priority: 'medium',
+      parent_task_id: null,
+      subtask_position: 0,
+      created_at: new Date().toISOString(),
+      updated_at: new Date().toISOString(),
+      metadata: {},
+      complexity: null,
+      assignee_id: null,
+      estimated_hours: null,
+      actual_hours: null,
+      due_date: null,
+      completed_at: null
+    };
+    const sub: TaskRow = {
+      ...parent,
+      id: 'uuid-sub-1',
+      display_id: 'T-1.1',
+      title: 'Sub',
+      parent_task_id: 'uuid-123',
+      subtask_position: 1
+    };
+    const task = TaskMapper.mapDatabaseTaskToTask(parent, [sub], new Map());
+    expect(task.id).toBe('T-1');
+    expect(task.subtasks[0].parentId).toBe('T-1');
+  });

Please run the test suite after applying the mapper fixes:

  • npx vitest run

Comment on lines 45 to +63
const subtasks: Subtask[] = dbSubtasks.map((subtask, index) => ({
id: index + 1, // Use numeric ID for subtasks
id: subtask.display_id || String(index + 1), // Use display_id if available (API storage), fallback to numeric (file storage)
parentId: dbTask.id,
title: subtask.title,
description: subtask.description || '',
status: this.mapStatus(subtask.status),
priority: this.mapPriority(subtask.priority),
dependencies: dependenciesByTaskId.get(subtask.id) || [],
details: (subtask.metadata as any)?.details || '',
testStrategy: (subtask.metadata as any)?.testStrategy || '',
details: this.extractMetadataField(subtask.metadata, 'details', ''),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Subtask.parentId should match exposed parent Task.id (display_id when present).

Currently uses dbTask.id, which desynchronizes references when display_id exists.

Apply this diff:

 const subtasks: Subtask[] = dbSubtasks.map((subtask, index) => ({
   id: subtask.display_id || String(index + 1),
-  parentId: dbTask.id,
+  parentId: dbTask.display_id || dbTask.id,
   title: subtask.title,
   description: subtask.description || '',
   status: this.mapStatus(subtask.status),
   priority: this.mapPriority(subtask.priority),
   dependencies: dependenciesByTaskId.get(subtask.id) || [],
πŸ€– Prompt for AI Agents
In packages/tm-core/src/mappers/TaskMapper.ts around lines 55 to 63, the
Subtask.parentId is set to dbTask.id which breaks references when the parent
Task exposes display_id; change parentId to use the exposed parent identifier
(dbTask.display_id if present, otherwise dbTask.id) so subtask.parentId matches
the Task.id consumers see, and ensure the value is coerced to a string if
needed.

Comment on lines +110 to +117
// Handle both old format (UUID string) and new format (object with display_id)
const dependencyId =
typeof dep.depends_on_task === 'object'
? dep.depends_on_task?.display_id
: dep.depends_on_task_id;
if (dependencyId) {
deps.push(dependencyId);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Legacy dependency grouping can drop IDs when display_id is null due to null being typeof 'object'.

Fallback to depends_on_task_id when display_id is missing.

Apply this diff:

-        // Handle both old format (UUID string) and new format (object with display_id)
-        const dependencyId =
-          typeof dep.depends_on_task === 'object'
-            ? dep.depends_on_task?.display_id
-            : dep.depends_on_task_id;
+        // Handle both formats; prefer display_id when present, else fallback to UUID
+        const dependencyId =
+          dep.depends_on_task?.display_id ?? dep.depends_on_task_id;
         if (dependencyId) {
           deps.push(dependencyId);
         }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Handle both old format (UUID string) and new format (object with display_id)
const dependencyId =
typeof dep.depends_on_task === 'object'
? dep.depends_on_task?.display_id
: dep.depends_on_task_id;
if (dependencyId) {
deps.push(dependencyId);
}
// Handle both formats; prefer display_id when present, else fallback to UUID
const dependencyId =
dep.depends_on_task?.display_id ?? dep.depends_on_task_id;
if (dependencyId) {
deps.push(dependencyId);
}
πŸ€– Prompt for AI Agents
In packages/tm-core/src/mappers/TaskMapper.ts around lines 110 to 117, the
current ternary picks dep.depends_on_task.display_id when depends_on_task is an
object even if display_id is null, causing IDs to be dropped; change the
conditional to prefer display_id only when it is non-null/defined (e.g. typeof
depends_on_task === 'object' && dep.depends_on_task?.display_id != null),
otherwise fall back to dep.depends_on_task_id, and keep the existing push only
when the resolved dependencyId is truthy.

Comment on lines 167 to 194
// Handle metadata fields (details, testStrategy, etc.)
// Load existing metadata to preserve fields not being updated
const { data: existingMetadataRow, error: existingMetadataError } =
await this.supabase
.from('tasks')
.select('metadata')
.eq('brief_id', briefId)
.eq('display_id', taskId.toUpperCase())
.single();

if (existingMetadataError) {
throw new Error(
`Failed to load existing task metadata: ${existingMetadataError.message}`
);
}

const metadata: Record<string, unknown> = {
...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {})
};

if (updates.details !== undefined) metadata.details = updates.details;
if (updates.testStrategy !== undefined)
metadata.testStrategy = updates.testStrategy;

if (Object.keys(metadata).length > 0) {
dbUpdates.metadata = metadata as Json;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Avoid unnecessary DB roundtrip for metadata.

You always SELECT metadata even when neither details nor testStrategy is being updated. Gate the fetch to those cases.

Apply this diff:

-    // Handle metadata fields (details, testStrategy, etc.)
-    // Load existing metadata to preserve fields not being updated
-    const { data: existingMetadataRow, error: existingMetadataError } =
-      await this.supabase
-        .from('tasks')
-        .select('metadata')
-        .eq('brief_id', briefId)
-        .eq('display_id', taskId.toUpperCase())
-        .single();
-
-    if (existingMetadataError) {
-      throw new Error(
-        `Failed to load existing task metadata: ${existingMetadataError.message}`
-      );
-    }
-
-    const metadata: Record<string, unknown> = {
-      ...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {})
-    };
-
-    if (updates.details !== undefined) metadata.details = updates.details;
-    if (updates.testStrategy !== undefined)
-      metadata.testStrategy = updates.testStrategy;
-
-    if (Object.keys(metadata).length > 0) {
-      dbUpdates.metadata = metadata as Json;
-    }
+    // Handle metadata fields (details, testStrategy, etc.)
+    if (updates.details !== undefined || updates.testStrategy !== undefined) {
+      // Load existing metadata to preserve fields not being updated
+      const { data: existingMetadataRow, error: existingMetadataError } =
+        await this.supabase
+          .from('tasks')
+          .select('metadata')
+          .eq('brief_id', briefId)
+          .eq('display_id', taskId.toUpperCase())
+          .single();
+
+      if (existingMetadataError) {
+        throw new Error(
+          `Failed to load existing task metadata: ${existingMetadataError.message}`
+        );
+      }
+
+      const metadata: Record<string, unknown> = {
+        ...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {})
+      };
+
+      if (updates.details !== undefined) metadata.details = updates.details;
+      if (updates.testStrategy !== undefined)
+        metadata.testStrategy = updates.testStrategy;
+
+      if (Object.keys(metadata).length > 0) {
+        dbUpdates.metadata = metadata as Json;
+      }
+    }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Handle metadata fields (details, testStrategy, etc.)
// Load existing metadata to preserve fields not being updated
const { data: existingMetadataRow, error: existingMetadataError } =
await this.supabase
.from('tasks')
.select('metadata')
.eq('brief_id', briefId)
.eq('display_id', taskId.toUpperCase())
.single();
if (existingMetadataError) {
throw new Error(
`Failed to load existing task metadata: ${existingMetadataError.message}`
);
}
const metadata: Record<string, unknown> = {
...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {})
};
if (updates.details !== undefined) metadata.details = updates.details;
if (updates.testStrategy !== undefined)
metadata.testStrategy = updates.testStrategy;
if (Object.keys(metadata).length > 0) {
dbUpdates.metadata = metadata as Json;
}
// Handle metadata fields (details, testStrategy, etc.)
if (updates.details !== undefined || updates.testStrategy !== undefined) {
// Load existing metadata to preserve fields not being updated
const { data: existingMetadataRow, error: existingMetadataError } =
await this.supabase
.from('tasks')
.select('metadata')
.eq('brief_id', briefId)
.eq('display_id', taskId.toUpperCase())
.single();
if (existingMetadataError) {
throw new Error(
`Failed to load existing task metadata: ${existingMetadataError.message}`
);
}
const metadata: Record<string, unknown> = {
...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {})
};
if (updates.details !== undefined) metadata.details = updates.details;
if (updates.testStrategy !== undefined)
metadata.testStrategy = updates.testStrategy;
if (Object.keys(metadata).length > 0) {
dbUpdates.metadata = metadata as Json;
}
}
πŸ€– Prompt for AI Agents
In packages/tm-core/src/repositories/supabase/supabase-task-repository.ts around
lines 167 to 194, the code always performs a SELECT to load existing metadata
even when neither updates.details nor updates.testStrategy are provided; modify
the logic to first check if at least one of those metadata fields is being
updated and only then perform the DB fetch and merge so we avoid an unnecessary
roundtrip. Specifically: gate the supabase.from('tasks').select('metadata') call
behind a condition that checks updates.details !== undefined ||
updates.testStrategy !== undefined, then keep the existing error handling, merge
existing metadata with the provided metadata fields, and assign
dbUpdates.metadata only when there are metadata changes.

Comment on lines +240 to +243
private mapPriorityToDatabase(
priority: string
): Database['public']['Enums']['task_priority'] {
switch (priority) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Narrow the priority param type.

Use the domain type for clarity and better type-safety.

Apply this diff:

-  private mapPriorityToDatabase(
-    priority: string
-  ): Database['public']['Enums']['task_priority'] {
+  private mapPriorityToDatabase(
+    priority: Task['priority']
+  ): Database['public']['Enums']['task_priority'] {
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private mapPriorityToDatabase(
priority: string
): Database['public']['Enums']['task_priority'] {
switch (priority) {
private mapPriorityToDatabase(
priority: Task['priority']
): Database['public']['Enums']['task_priority'] {
switch (priority) {
πŸ€– Prompt for AI Agents
In packages/tm-core/src/repositories/supabase/supabase-task-repository.ts around
lines 240 to 243, the mapPriorityToDatabase function accepts a plain string;
change its parameter to the domain priority type (use the existing domain type
for task priority, e.g. TaskPriority or whatever the project defines) to improve
type-safety, import that type at the top of the file, update the function
signature to use it instead of string, and ensure the switch cases and any
callers still compile (adjust callers if they pass raw strings by
converting/validating to the domain type before calling).

Comment on lines +85 to 90
* Subtask interface extending Task
* ID can be number (file storage) or string (API storage with display_id)
*/
export interface Subtask extends Omit<Task, 'id' | 'subtasks'> {
id: number;
id: number | string;
parentId: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Type guard mismatch: Subtask.id widened to string | number, but isSubtask still enforces number.

This will reject valid subtasks with string IDs (e.g., display_id from API storage).

Apply this diff:

 export function isSubtask(obj: unknown): obj is Subtask {
   if (!obj || typeof obj !== 'object') return false;
   const subtask = obj as Record<string, unknown>;

   return (
-    typeof subtask.id === 'number' &&
+    (typeof subtask.id === 'number' || typeof subtask.id === 'string') &&
     typeof subtask.parentId === 'string' &&
     typeof subtask.title === 'string' &&
     typeof subtask.description === 'string' &&
     isTaskStatus(subtask.status) &&
     isTaskPriority(subtask.priority) &&
     !('subtasks' in subtask)
   );
 }

Also applies to: 234-243

πŸ€– Prompt for AI Agents
In packages/tm-core/src/types/index.ts around lines 85-90 (and similarly lines
234-243), the Subtask interface was changed so id is number | string but the
isSubtask type guard still only accepts number IDs; update the isSubtask
implementation(s) to allow both string and number IDs (e.g., check typeof id ===
'number' || typeof id === 'string' and ensure parentId is present), and adjust
the guard's narrowing/return type accordingly so string-based subtasks
(display_id) are not rejected.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
apps/cli/src/commands/list.command.ts (1)

284-299: Bug: nextTask subtask IDs aren’t resolved to objects (breaks dashboard/recommendation).

When findNextTask returns an id like "5.2", tasks.find(...) against top-level ids fails, so nextTask becomes undefined. Resolve parent/subtask explicitly and pass correct data to dashboards and recommendation.

Apply this fix:

-    const nextTask = nextTaskInfo
-      ? tasks.find((t) => String(t.id) === String(nextTaskInfo.id))
-      : undefined;
+    const nextTaskResolved = nextTaskInfo
+      ? (() => {
+          const idStr = String(nextTaskInfo.id);
+          if (idStr.includes('.')) {
+            const [parentId, subId] = idStr.split('.');
+            const parent = tasks.find((t) => String(t.id) === parentId);
+            const sub = parent?.subtasks?.find((st) => String(st.id) === subId);
+            return parent && sub ? { kind: 'subtask' as const, parent, sub } : undefined;
+          }
+          const task = tasks.find((t) => String(t.id) === idStr);
+          return task ? { kind: 'task' as const, task } : undefined;
+        })()
+      : undefined;
@@
-    displayDashboards(
+    displayDashboards(
       taskStats,
       subtaskStats,
       priorityBreakdown,
       depStats,
-      nextTask
+      nextTaskResolved
+        ? nextTaskResolved.kind === 'task'
+          ? nextTaskResolved.task
+          : nextTaskResolved.parent
+        : undefined
     );
@@
-    if (nextTask) {
-      const description = getTaskDescription(nextTask);
-      displayRecommendedNextTask({
-        id: nextTask.id,
-        title: nextTask.title,
-        priority: nextTask.priority,
-        status: nextTask.status,
-        dependencies: nextTask.dependencies,
-        description,
-        complexity: nextTask.complexity as number | undefined
-      });
+    if (nextTaskResolved && nextTaskInfo) {
+      const displayId = String(nextTaskInfo.id);
+      const payload =
+        nextTaskResolved.kind === 'task'
+          ? {
+              id: displayId,
+              title: nextTaskResolved.task.title,
+              priority: nextTaskResolved.task.priority,
+              status: nextTaskResolved.task.status,
+              dependencies: nextTaskResolved.task.dependencies?.map(String),
+              description: getTaskDescription(nextTaskResolved.task),
+              complexity: (nextTaskResolved.task as any).complexity as number | undefined
+            }
+          : {
+              id: displayId,
+              title: nextTaskResolved.sub.title || `Subtask ${displayId}`,
+              priority:
+                nextTaskResolved.sub.priority || nextTaskResolved.parent.priority,
+              status: nextTaskResolved.sub.status,
+              dependencies: (nextTaskResolved.sub.dependencies || []).map(String),
+              description:
+                (nextTaskResolved.sub as any).description ??
+                ((nextTaskResolved.sub as any).details
+                  ? String((nextTaskResolved.sub as any).details)
+                      .split('\n')[0]
+                      .split('.')[0]
+                  : undefined),
+              complexity: (nextTaskResolved.sub as any).complexity as number | undefined
+            };
+      displayRecommendedNextTask(payload);
     } else {
       displayRecommendedNextTask(undefined);
     }

Also applies to: 309-321

apps/cli/src/commands/context.command.ts (2)

353-358: Fix return message to use defined brief label

selectedBrief.name is not set in choices, resulting in β€œundefined”. Use briefName (already computed) or a fallback.

- return {
-   success: true,
-   action: 'select-brief',
-   context: this.authManager.getContext() || undefined,
-   message: `Selected brief: ${selectedBrief.name}`
- };
+ return {
+   success: true,
+   action: 'select-brief',
+   context: this.authManager.getContext() || undefined,
+   message: `Selected brief: ${briefName}`
+ };

470-473: Provide a safe default for TM_PUBLIC_BASE_DOMAIN in help text

If the env is unset, message shows β€œhttps://undefined/...”. Add a fallback.

- ui.displayError(
-   `Provide a valid brief ID or a Hamster brief URL, e.g. https://${process.env.TM_PUBLIC_BASE_DOMAIN}/home/hamster/briefs/<id>`
- );
+ const base = process.env.TM_PUBLIC_BASE_DOMAIN || 'app.tryhamster.com';
+ ui.displayError(
+   `Provide a valid brief ID or a Hamster brief URL, e.g. https://${base}/home/hamster/briefs/<id>`
+ );
apps/cli/src/commands/start.command.ts (1)

293-303: Remove process signal listeners after child exits

Avoid accumulating listeners in tests/long-lived processes.

- process.on('SIGINT', cleanup);
- process.on('SIGTERM', cleanup);
- process.on('exit', cleanup);
+ const onSigInt = cleanup;
+ const onSigTerm = cleanup;
+ const onExit = cleanup;
+ process.on('SIGINT', onSigInt);
+ process.on('SIGTERM', onSigTerm);
+ process.on('exit', onExit);
+ const removeListeners = () => {
+   process.off('SIGINT', onSigInt);
+   process.off('SIGTERM', onSigTerm);
+   process.off('exit', onExit);
+ };
+ childProcess.on('close', () => removeListeners());
+ childProcess.on('error', () => removeListeners());
apps/cli/src/commands/auth.command.ts (1)

221-223: Unify CLI binary name in help text

Elsewhere you use β€œtm”; this says β€œtask-master”. Align for consistency.

- console.log(
-   chalk.gray('\n  Run "task-master auth login" to authenticate')
- );
+ console.log(chalk.gray('\n  Run "tm auth login" to authenticate'));
♻️ Duplicate comments (2)
packages/tm-core/src/storage/file-storage/file-storage.ts (2)

24-31: Stale complexity cache after mutating ops

After introducing complexityManager, none of the write paths (saveTasks, deleteTag, renameTag, etc.) clear the per-tag cache. Any task mutation now leaves ComplexityReportManager serving stale entries, so subsequent loadTasks returns outdated complexity data until the process restarts. Please call this.complexityManager.clearCache(resolvedTag) (and clear affected tags in rename/delete flows) once writes succeed.

 await this.fileOps.writeJson(filePath, existingData);
+		this.complexityManager.clearCache(resolvedTag);

Propagate similar invalidations to other write paths that bypass saveTasks.


96-121: Make complexity enrichment opt-in

loadTasks now always calls enrichTasksWithComplexity. For tags without a report this issues an fs.access + ENOENT handling every read because ComplexityReportManager doesn’t cache negative lookups. High-volume reads (CLI listing, metadata updates) now incur wasted disk I/O and JSON parsing with no benefit, matching the previously raised latency concern. Please gate enrichment behind an option (e.g., options?.includeComplexity) or otherwise short-circuit when callers don’t need it, caching β€œno report” results if enrichment is requested.

πŸ“œ Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between db6f405 and b9e644c.

πŸ“’ Files selected for processing (25)
  • .changeset/pre.json (1 hunks)
  • CHANGELOG.md (1 hunks)
  • apps/cli/src/command-registry.ts (1 hunks)
  • apps/cli/src/commands/auth.command.ts (1 hunks)
  • apps/cli/src/commands/context.command.ts (1 hunks)
  • apps/cli/src/commands/export.command.ts (1 hunks)
  • apps/cli/src/commands/list.command.ts (5 hunks)
  • apps/cli/src/commands/set-status.command.ts (1 hunks)
  • apps/cli/src/commands/show.command.ts (1 hunks)
  • apps/cli/src/commands/start.command.ts (1 hunks)
  • apps/cli/src/index.ts (1 hunks)
  • package.json (7 hunks)
  • packages/tm-core/src/errors/task-master-error.ts (1 hunks)
  • packages/tm-core/src/index.ts (2 hunks)
  • packages/tm-core/src/interfaces/storage.interface.ts (3 hunks)
  • packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (1 hunks)
  • packages/tm-core/src/repositories/task-repository.interface.ts (1 hunks)
  • packages/tm-core/src/services/export.service.ts (1 hunks)
  • packages/tm-core/src/services/index.ts (1 hunks)
  • packages/tm-core/src/services/task-service.ts (3 hunks)
  • packages/tm-core/src/storage/api-storage.ts (4 hunks)
  • packages/tm-core/src/storage/file-storage/file-storage.ts (5 hunks)
  • packages/tm-core/src/task-master-core.ts (6 hunks)
  • scripts/modules/commands.js (11 hunks)
  • tsdown.config.ts (2 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (7)
.changeset/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/new_features.mdc)

Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.

Files:

  • .changeset/pre.json
package.json

πŸ“„ CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

Add and update test scripts in package.json to include test, test:watch, test:coverage, test:unit, test:integration, test:e2e, and test:ci

Files:

  • package.json
scripts/modules/commands.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/ai_services.mdc)

scripts/modules/commands.js: Centralize all LLM calls through generateTextService or generateObjectService.
Do not import or call anything from the old ai-services.js, ai-client-factory.js, or ai-client-utils.js files.
Do not fetch AI-specific parameters (model ID, max tokens, temp) using config-manager.js getters for the AI call. Pass the role instead.
Do not implement fallback or retry logic outside ai-services-unified.js.
Do not handle API key resolution outside the service layer (it uses utils.js internally).
Determine the appropriate role (main, research, fallback) in your core logic and pass it to the service.
Pass the session object (received in the context parameter, especially from direct function wrappers) to the service call when in MCP context.
Use generateTextService and implement robust manual JSON parsing (with Zod validation after parsing) when structured output is needed, as generateObjectService has shown unreliability with some providers/schemas.
Be aware of potential reliability issues with generateObjectService across different providers and complex schemas. Prefer generateTextService + manual parsing as a more robust alternative for structured data needs.

scripts/modules/commands.js: All new user-facing commands should be added to 'scripts/modules/commands.js'.
Use consistent patterns for option naming and help text in CLI commands.
Follow the Commander.js model for subcommand structure in CLI commands.
When using callbacks (like in Commander.js commands), define them separately to allow testing the callback logic independently.
Add help text to the command definition and update 'dev_workflow.mdc' with command reference when adding a new feature.
Follow the established pattern in 'commands.js' for CLI command implementation, using Commander.js for argument parsing, including comprehensive help text and examples, and supporting tagged task context awareness.
Provide clear error messages for common failu...

Files:

  • scripts/modules/commands.js
scripts/modules/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Each module in scripts/modules/ should be focused on a single responsibility, following the modular architecture (e.g., commands.js for CLI command handling, task-manager.js for task data and core logic, dependency-manager.js for dependency management, ui.js for CLI output formatting, ai-services-unified.js for AI service integration, config-manager.js for configuration management, utils.js for utility functions).

scripts/modules/*.js: Export all core functions, helper functions, and utility methods needed by your new function or command from their respective modules. Explicitly review the module's export block to ensure every required dependency is included.
Pass all required parameters to functions you call within your implementation and verify that direct function parameters match their core function counterparts.
Use consistent file naming conventions: 'task_${id.toString().padStart(3, '0')}.txt', use path.join for composing file paths, and use appropriate file extensions (.txt for tasks, .json for data).
Use structured error objects with code and message properties, include clear error messages, and handle both function-specific and file system errors.
Import all silent mode utilities together from 'scripts/modules/utils.js' and always use isSilentMode() to check global silent mode status. Wrap core function calls within direct functions using enableSilentMode() and disableSilentMode() in a try/finally block if the core function might produce console output.
Core functions should check outputFormat === 'text' before displaying UI elements and use internal logging that respects silent mode.
Design functions to accept dependencies as parameters (dependency injection) and avoid hard-coded dependencies that are difficult to mock.
Keep pure logic separate from I/O operations or UI rendering to allow testing the logic without mocking complex dependencies.
When implementing core logic for new features, do so in 'scripts/modules/' before CLI or MCP interfaces, and d...

Files:

  • scripts/modules/commands.js
scripts/modules/**

πŸ“„ CodeRabbit inference engine (.cursor/rules/dev_workflow.mdc)

When using the MCP server, restart it if core logic in scripts/modules or MCP tool/direct function definitions change.

Files:

  • scripts/modules/commands.js
scripts/modules/*

πŸ“„ CodeRabbit inference engine (.cursor/rules/tags.mdc)

scripts/modules/*: Every command that reads or writes tasks.json must be tag-aware
All command files must import getCurrentTag from utils.js
Every CLI command that operates on tasks must include the --tag CLI option
All commands must resolve the tag using the pattern: options.tag || getCurrentTag(projectRoot) || 'master'
All commands must find projectRoot with error handling before proceeding
All commands must pass { projectRoot, tag } as context to core functions
MCP direct functions must accept and use a context object containing projectRoot and tag, and pass them to core functions
Do not hard-code tag resolution (e.g., const tag = options.tag || 'master';); always use getCurrentTag
Do not omit the --tag CLI option in commands that operate on tasks
Do not omit the context parameter when calling core functions from commands
Do not call readJSON or writeJSON without passing projectRoot and tag

Files:

  • scripts/modules/commands.js
**/*.js

πŸ“„ CodeRabbit inference engine (.cursor/rules/tests.mdc)

**/*.js: Declare and initialize global variables at the top of modules to avoid hoisting issues.
Use proper function declarations to avoid hoisting issues and initialize variables before they are referenced.
Do not reference variables before their declaration in module scope.
Use dynamic imports (import()) to avoid initialization order issues in modules.

Files:

  • scripts/modules/commands.js
🧠 Learnings (23)
πŸ“š Learning: 2025-09-26T19:05:47.555Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: packages/ai-sdk-provider-grok-cli/package.json:11-13
Timestamp: 2025-09-26T19:05:47.555Z
Learning: In the eyaltoledano/claude-task-master repository, internal tm/ packages use a specific export pattern where the "exports" field points to TypeScript source files (./src/index.ts) while "main" points to compiled output (./dist/index.js) and "types" points to source files (./src/index.ts). This pattern is used consistently across internal packages like tm/core and tm/ai-sdk-provider-grok-cli because they are consumed directly during build-time bundling with tsdown rather than being published as separate packages.

Applied to files:

  • packages/tm-core/src/index.ts
  • packages/tm-core/src/services/index.ts
  • packages/tm-core/src/task-master-core.ts
πŸ“š Learning: 2025-07-31T22:07:49.716Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-31T22:07:49.716Z
Learning: Applies to scripts/modules/commands.js : Export the registerCommands function and keep the CLI setup code clean and maintainable.

Applied to files:

  • apps/cli/src/index.ts
  • apps/cli/src/command-registry.ts
  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use AI to generate detailed subtasks within the current tag context, considering complexity analysis for subtask counts and ensuring proper IDs for newly created subtasks.

Applied to files:

  • packages/tm-core/src/storage/file-storage/file-storage.ts
πŸ“š Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to .changeset/* : Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.

Applied to files:

  • .changeset/pre.json
πŸ“š Learning: 2025-08-03T12:13:33.875Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-08-03T12:13:33.875Z
Learning: Applies to package.json : Add and update test scripts in package.json to include test, test:watch, test:coverage, test:unit, test:integration, test:e2e, and test:ci

Applied to files:

  • package.json
πŸ“š Learning: 2025-09-26T19:03:33.225Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: package.json:130-132
Timestamp: 2025-09-26T19:03:33.225Z
Learning: In the eyaltoledano/claude-task-master repository, packages are bundled using tsdown during the build process, which means dependencies imported by the source code (including tm internal packages like tm/ai-sdk-provider-grok-cli) are included in the final bundle and don't need to be available as separate runtime dependencies, so they should remain as devDependencies rather than being moved to dependencies.

Applied to files:

  • package.json
πŸ“š Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to src/ai-providers/*.js : Provider modules must import the provider's create<ProviderName> function from ai-sdk/<provider-name>, and import generateText, streamText, generateObject from the core ai package, as well as the log utility from ../../scripts/modules/utils.js.

Applied to files:

  • package.json
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Extract tasks from PRD documents using AI, create them in the current tag context (defaulting to 'master'), provide clear prompts to guide AI task generation, and validate/clean up AI-generated tasks.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to scripts/modules/utils.js : Use tagged task system aware functions for task finding and manipulation, handle both task and subtask operations, and validate task IDs before operations.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:07:39.336Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-07-18T17:07:39.336Z
Learning: Applies to scripts/modules/task-manager/*.js : Files in scripts/modules/task-manager/ should each handle a specific action related to task management (e.g., add-task.js, expand-task.js), supporting the tagged task lists system and backward compatibility.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Provide functions for updating task status within the current tag context, handling both individual tasks and subtasks, and considering subtask status when updating parent tasks.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Tasks must be accessed and updated through the tag resolution layer using getTasksForTag(data, tagName) and setTasksForTag(data, tagName, tasks); direct manipulation of the tagged structure in core functions is not allowed.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Tasks must be organized into separate contexts (tags) within tasks.json, using the tagged format: {"master": {"tasks": [...]}, "feature-branch": {"tasks": [...]}}. Legacy format {"tasks": [...]} must be silently migrated to the tagged format on first use.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use tag resolution functions to maintain backward compatibility, returning legacy format to core functions and not exposing the tagged structure to existing core logic.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Generate task files from the current tag context, include tag information in generated files, and do not mix tasks from different tags in file generation.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/task-manager.js : Features that create, read, update, or delete tasks belong in 'scripts/modules/task-manager.js'.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:09:40.548Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:40.548Z
Learning: Applies to scripts/modules/dependency-manager.js : Provide clear error messages for non-existent dependencies

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-09-24T15:12:12.658Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/.windsurfrules:0-0
Timestamp: 2025-09-24T15:12:12.658Z
Learning: Manage dependencies with task-master add-dependency and remove-dependency; validate and fix using validate-dependencies and fix-dependencies

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/dependency-manager.js : Features that handle task relationships belong in 'scripts/modules/dependency-manager.js'.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Check for existing dependencies to prevent duplicates

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Format dependency lists consistently for visualization

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-31T22:08:16.039Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/taskmaster.mdc:0-0
Timestamp: 2025-07-31T22:08:16.039Z
Learning: Applies to .taskmaster/config.json : All other Taskmaster settings (model choice, max tokens, temperature, log level, custom endpoints) are managed in .taskmaster/config.json via the task-master models command or models MCP tool.

Applied to files:

  • scripts/modules/commands.js
πŸ“š Learning: 2025-07-18T17:10:12.881Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:12.881Z
Learning: For CLI usage, install Taskmaster globally with `npm install -g task-master-ai` or use locally via `npx task-master-ai ...`.

Applied to files:

  • scripts/modules/commands.js
🧬 Code graph analysis (12)
packages/tm-core/src/repositories/task-repository.interface.ts (1)
packages/tm-core/src/interfaces/storage.interface.ts (1)
  • LoadTasksOptions (11-16)
packages/tm-core/src/storage/api-storage.ts (1)
packages/tm-core/src/interfaces/storage.interface.ts (1)
  • LoadTasksOptions (11-16)
packages/tm-core/src/services/task-service.ts (3)
packages/tm-core/src/logger/factory.ts (1)
  • getLogger (23-44)
packages/tm-core/src/entities/task.entity.ts (1)
  • TaskEntity (17-275)
packages/tm-core/src/logger/logger.ts (1)
  • error (163-166)
packages/tm-core/src/storage/file-storage/file-storage.ts (3)
packages/tm-core/src/reports/complexity-report-manager.ts (1)
  • ComplexityReportManager (21-185)
packages/tm-core/src/interfaces/storage.interface.ts (1)
  • LoadTasksOptions (11-16)
packages/tm-core/src/types/index.ts (1)
  • Task (57-82)
packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (6)
packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1)
  • DependencyFetcher (8-68)
packages/tm-core/src/types/database.types.ts (2)
  • Database (9-411)
  • Json (1-7)
packages/tm-core/src/interfaces/storage.interface.ts (1)
  • LoadTasksOptions (11-16)
packages/tm-core/src/types/index.ts (1)
  • Task (57-82)
packages/tm-core/src/types/repository-types.ts (2)
  • TaskWithRelations (9-16)
  • TaskDatabaseUpdate (40-41)
packages/tm-core/src/mappers/TaskMapper.ts (1)
  • TaskMapper (12-216)
packages/tm-core/src/interfaces/storage.interface.ts (1)
packages/tm-core/src/types/index.ts (2)
  • TaskStatus (20-28)
  • Task (57-82)
apps/cli/src/commands/list.command.ts (1)
apps/cli/src/ui/components/next-task.component.ts (2)
  • getTaskDescription (125-141)
  • displayRecommendedNextTask (27-120)
packages/tm-core/src/services/export.service.ts (2)
packages/tm-core/src/errors/task-master-error.ts (2)
  • TaskMasterError (130-329)
  • ERROR_CODES (9-56)
packages/tm-core/src/storage/file-storage/file-storage.ts (1)
  • FileStorage (20-662)
apps/cli/src/command-registry.ts (8)
apps/cli/src/index.ts (11)
  • CommandMetadata (20-20)
  • CommandRegistry (17-17)
  • ListTasksCommand (7-7)
  • ShowCommand (8-8)
  • StartCommand (11-11)
  • SetStatusCommand (12-12)
  • ExportCommand (13-13)
  • AuthCommand (9-9)
  • ContextCommand (10-10)
  • registerAllCommands (18-18)
  • registerCommandsByCategory (19-19)
apps/cli/src/commands/list.command.ts (1)
  • ListTasksCommand (60-484)
apps/cli/src/commands/show.command.ts (1)
  • ShowCommand (47-332)
apps/cli/src/commands/start.command.ts (1)
  • StartCommand (44-503)
apps/cli/src/commands/set-status.command.ts (1)
  • SetStatusCommand (57-297)
apps/cli/src/commands/export.command.ts (1)
  • ExportCommand (32-379)
apps/cli/src/commands/auth.command.ts (1)
  • AuthCommand (32-503)
apps/cli/src/commands/context.command.ts (1)
  • ContextCommand (31-704)
packages/tm-core/src/task-master-core.ts (3)
packages/tm-core/src/services/export.service.ts (3)
  • ExportService (86-496)
  • ExportTasksOptions (39-50)
  • ExportResult (55-71)
packages/tm-core/src/auth/auth-manager.ts (1)
  • AuthManager (26-280)
packages/tm-core/src/auth/types.ts (1)
  • UserContext (16-22)
scripts/modules/commands.js (3)
apps/cli/src/command-registry.ts (1)
  • registerAllCommands (238-240)
apps/cli/src/index.ts (1)
  • registerAllCommands (18-18)
scripts/modules/task-manager/models.js (4)
  • options (149-149)
  • options (277-277)
  • options (368-368)
  • options (656-656)
apps/cli/src/commands/export.command.ts (2)
packages/tm-core/src/services/export.service.ts (1)
  • ExportResult (55-71)
packages/tm-core/src/task-master-core.ts (2)
  • ExportResult (59-59)
  • TaskMasterCore (66-350)
πŸͺ› markdownlint-cli2 (0.18.1)
CHANGELOG.md

46-46: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


53-53: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


59-59: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

πŸ”‡ Additional comments (26)
packages/tm-core/src/services/index.ts (1)

8-13: Exports look correct

Re-exporting ExportService and its option/result types keeps the barrel in sync with the new service API. Good addition.

packages/tm-core/src/index.ts (2)

14-16: Exported Types Verified: ConflictCheckResult, ExportTasksOptions, and ExportResult are correctly declared and exported from task-master-core.ts and re-exported in index.ts.


67-74: Exports verified ComplexityReportManager and all report types are correctly re-exported in packages/tm-core/src/reports/index.ts.

packages/tm-core/src/errors/task-master-error.ts (1)

54-56: NOT_FOUND error code addition looks good

The new entry keeps the enum-style map consistent and broadens downstream matching as expected.

packages/tm-core/src/repositories/task-repository.interface.ts (1)

2-6: Repository signature update is aligned

Importing LoadTasksOptions and extending getTasks with the optional options argument keeps the repo contract in sync with storage. Looks good to me.

packages/tm-core/src/interfaces/storage.interface.ts (1)

8-40: LoadTasksOptions integration checks out

Defining LoadTasksOptions and threading it through IStorage/BaseStorage gives a clean extension point for pushing filters down to storage. Nicely structured.

packages/tm-core/src/storage/api-storage.ts (1)

7-167: API storage now forwarding filter options correctly

Import updates and passing options through to repository.getTasks make the API backend participate in the new filter flow. Implementation stays consistent with existing tagging context.

packages/tm-core/src/services/task-service.ts (1)

96-103: Guard optional filter before dereferencing

When options.filter is omitted (the default call path), options.filter.priority on Line 98 throws TypeError: Cannot read properties of undefined. Please cache options.filter and use optional chaining (or similar) for all subsequent accesses so we safely handle the no-filter case.

-			const canPushStatusFilter =
-				options.filter?.status &&
-				!options.filter.priority &&
-				!options.filter.tags &&
-				!options.filter.assignee &&
-				!options.filter.search &&
-				options.filter.hasSubtasks === undefined;
+			const filter = options.filter;
+			const canPushStatusFilter =
+				!!filter?.status &&
+				!filter?.priority &&
+				!filter?.tags &&
+				!filter?.assignee &&
+				!filter?.search &&
+				filter?.hasSubtasks === undefined;

Likely an incorrect or invalid review comment.

.changeset/pre.json (1)

1-26: LGTM! Pre-release configuration is correctly structured.

The pre-release configuration properly sets up the RC flow with:

  • RC tag for pre-release versions
  • Initial versions matching the baseline (0.27.3)
  • Comprehensive list of changesets to be included in the release
tsdown.config.ts (1)

3-7: LGTM! Clean migration to standard dotenv.

The migration from dotenv-mono to standard dotenv with explicit absolute path resolution is a solid improvement. Using resolve(process.cwd(), '.env') ensures the correct .env file is loaded regardless of the working directory.

package.json (4)

3-3: Version bump aligns with pre-release configuration.

The version bump to 0.28.0-rc.2 correctly reflects the RC pre-release flow configured in .changeset/pre.json.


20-20: Good practice: Explicit NODE_ENV for tests.

Setting NODE_ENV=test explicitly ensures consistent test behavior across environments.


131-131: Internal Grok CLI provider package verified.

  • Implements ProviderV2 and exports createGrokCli/grokCli.
  • Imported in src/ai-providers/grok-cli.js.
  • Covered by unit tests (packages/ai-sdk-provider-grok-cli/src/grok-cli-provider.test.ts) and integration tests (tests/integration/providers/temperature-support.test.js).

55-103: Verify major dependency upgrades and integration code

  • No deprecated AI SDK v4 patterns remain; v5 imports (generateObject, generateText, streamText) are used in src/ai-providers/gemini-cli.jsβ€”replace the commented legacy import in scripts/modules/ai-services-unified.js.
  • Review all Zod schemas for v4 breaking changes (unified error API, default unknown‐key behavior; opt into .passthrough() or .strict()).
  • Confirm OpenRouter provider calls (createOpenRouter) align with v1 factory API and updated providerOptions.
apps/cli/src/index.ts (2)

13-13: Good addition of ExportCommand export.

Public surface updated cleanly; no issues.


15-21: Command registry re-exports look correct.

Consistent named and type re-exports for registry APIs. Matches consumers expecting centralized registration.

apps/cli/src/commands/show.command.ts (1)

325-331: Standardized register API looks good.

Returning the command instance improves composability and aligns with registry usage.

apps/cli/src/commands/list.command.ts (1)

479-483: Register API alignment looks good.

Returning the ListTasksCommand instance aligns with registry usage.

scripts/modules/commands.js (4)

17-23: Importing registry utilities from @tm/cli looks correct.

Keeps this module lean; reuses centralized command definitions.


1813-1814: Wording update LGTM.

β€œUse configured research model” is clearer and provider-agnostic.


1670-1675: Centralized command registration: no name collisions detected. Verified that none of the commands (list, show, start, set-status, export, auth, context) are defined locally in scripts/modules/commands.js.


3552-3555: Codex CLI provider flag support verified end-to-end. setModel(), config-manager, model registry, docs/models, and examples include codex-cli.

apps/cli/src/commands/context.command.ts (1)

697-703: Registration API change looks good

Static register(program, name?) returning the command instance aligns with the new registry model.

apps/cli/src/commands/start.command.ts (1)

496-502: Registration method LGTM

Consistent with the centralized registry pattern.

apps/cli/src/commands/auth.command.ts (1)

496-502: Registration method LGTM

Constructor name param + static register(program, name?) pattern matches other commands.

apps/cli/src/commands/export.command.ts (1)

95-101: Avoid direct process.exit in export.command.ts; use this.error and program.exitOverride

  • In export.command.ts (lines 99, 122, 131, 138, 151 & 201), replace each ui.displayError(...) + process.exit(1), spinner.fail(...) + process.exit(1), and the process.exit(0) on cancellation with Commander’s this.error('…') (non-zero) or return/this.exit(0) (zero).
  • In your CLI bootstrap (e.g., apps/cli/src/index.ts), invoke program.exitOverride() before .parse() so this.error() flows through without killing the process.
β›” Skipped due to learnings
Learnt from: joedanz
PR: eyaltoledano/claude-task-master#748
File: scripts/modules/task-manager/parse-prd.js:726-733
Timestamp: 2025-07-21T17:51:07.239Z
Learning: In CLI contexts within task-manager modules like scripts/modules/task-manager/parse-prd.js, using process.exit(1) for validation failures and error conditions is correct and preferred over throwing errors, as it provides immediate termination with appropriate exit codes for scripting. The code should distinguish between MCP contexts (throw errors) and CLI contexts (use process.exit).

Comment on lines +20 to +25
export interface CommandMetadata {
name: string;
description: string;
commandClass: typeof Command;
category?: 'task' | 'auth' | 'utility' | 'development';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Tighten typing for command constructors; avoid any casts.

Define a constructor type that optionally includes static register/registerOn, and use it in metadata/registration. This preserves compile-time safety.

 export interface CommandMetadata {
   name: string;
   description: string;
-  commandClass: typeof Command;
+  commandClass: RegistrableCommandCtor;
   category?: 'task' | 'auth' | 'utility' | 'development';
 }
+
+type RegistrableCommandCtor = {
+  new (name?: string): Command;
+  register?: (program: Command, name?: string) => unknown;
+  registerOn?: (program: Command) => unknown;
+};
@@
-  private static registerCommand(
-    program: Command,
-    metadata: CommandMetadata
-  ): void {
-    const CommandClass = metadata.commandClass as any;
+  private static registerCommand(
+    program: Command,
+    metadata: CommandMetadata
+  ): void {
+    const CommandClass = metadata.commandClass;
@@
-    if (CommandClass.registerOn) {
+    if (CommandClass.registerOn) {
       CommandClass.registerOn(program);
-    } else if (CommandClass.register) {
+    } else if (CommandClass.register) {
       CommandClass.register(program);
     } else {
       // Fallback to creating instance and adding
-      const instance = new CommandClass();
+      const instance = new CommandClass();
       program.addCommand(instance);
     }
   }

Also applies to: 129-145

Comment on lines +135 to +141
// Use the static registration method that all commands have
if (CommandClass.registerOn) {
CommandClass.registerOn(program);
} else if (CommandClass.register) {
CommandClass.register(program);
} else {
// Fallback to creating instance and adding
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Legacy registerOn fallback retained.

Ok for transition; consider removing once all commands adopt static register(program, name?).

πŸ€– Prompt for AI Agents
In apps/cli/src/command-registry.ts around lines 135-141 the code still keeps
the legacy registerOn and instance-creation fallback; remove the else branch
that falls back to creating a Command instance and the registerOn path so the
registry always calls the modern static register(program, name?) method on
CommandClass; update the Command type/interface to require static
register(program, name?) and adjust the callsite to pass the name if needed,
then run tests and update any command modules that still implement registerOn or
instance registration to the new static signature.

Comment on lines +74 to +83
try {
// Initialize TaskMasterCore
this.taskMasterCore = await TaskMasterCore.create({
projectPath: process.cwd()
});
} catch (error) {
throw new Error(
`Failed to initialize services: ${(error as Error).message}`
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Preserve error cause when wrapping initialization errors

Keep original stack/cause for debugging.

- throw new Error(
-   `Failed to initialize services: ${(error as Error).message}`
- );
+ throw new Error('Failed to initialize services', { cause: error as Error });
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
// Initialize TaskMasterCore
this.taskMasterCore = await TaskMasterCore.create({
projectPath: process.cwd()
});
} catch (error) {
throw new Error(
`Failed to initialize services: ${(error as Error).message}`
);
}
try {
// Initialize TaskMasterCore
this.taskMasterCore = await TaskMasterCore.create({
projectPath: process.cwd()
});
} catch (error) {
throw new Error('Failed to initialize services', { cause: error as Error });
}
πŸ€– Prompt for AI Agents
In apps/cli/src/commands/export.command.ts around lines 74 to 83, the catch
block currently rethrows a new Error and loses the original error's stack/cause;
update the throw to preserve the original error by passing it as the cause (for
example: throw new Error('Failed to initialize services', { cause: error })) or
rethrow the original error after annotating, ensuring the original stack and
error object are retained for debugging.

Comment on lines +198 to +203
} catch (error: any) {
if (spinner?.isSpinning) spinner.fail('Export failed');
this.handleError(error);
process.exit(1);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

Set lastResult on failure before exiting

So programmatic callers/tests can inspect failure details.

} catch (error: any) {
  if (spinner?.isSpinning) spinner.fail('Export failed');
  this.handleError(error);
+ this.lastResult = { success: false, action: 'export', message: error?.message || 'Export failed' };
  process.exit(1);
}
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (error: any) {
if (spinner?.isSpinning) spinner.fail('Export failed');
this.handleError(error);
process.exit(1);
}
}
} catch (error: any) {
if (spinner?.isSpinning) spinner.fail('Export failed');
this.handleError(error);
this.lastResult = { success: false, action: 'export', message: error?.message || 'Export failed' };
process.exit(1);
}
}
πŸ€– Prompt for AI Agents
In apps/cli/src/commands/export.command.ts around lines 198 to 203, the catch
block exits without setting the command's lastResult, so programmatic
callers/tests can't inspect failure details; before calling process.exit(1) (and
preferably before spinner.fail), assign this.lastResult = { success: false,
error: extract relevant error fields (e.g. message and stack or serialized
error), code: optional error.code } so callers can inspect the failure, then
call spinner.fail and process.exit(1).

Comment on lines +238 to +284
private extractBriefId(input: string): string | null {
const raw = input?.trim() ?? '';
if (!raw) return null;

const parseUrl = (s: string): URL | null => {
try {
return new URL(s);
} catch {}
try {
return new URL(`https://${s}`);
} catch {}
return null;
};

const fromParts = (path: string): string | null => {
const parts = path.split('/').filter(Boolean);
const briefsIdx = parts.lastIndexOf('briefs');
const candidate =
briefsIdx >= 0 && parts.length > briefsIdx + 1
? parts[briefsIdx + 1]
: parts[parts.length - 1];
return candidate?.trim() || null;
};

// Try URL parsing
const url = parseUrl(raw);
if (url) {
const qId = url.searchParams.get('id') || url.searchParams.get('briefId');
const candidate = (qId || fromParts(url.pathname)) ?? null;
if (candidate) {
if (this.isLikelyId(candidate) || candidate.length >= 8) {
return candidate;
}
}
}

// Check if it looks like a path
if (raw.includes('/')) {
const candidate = fromParts(raw);
if (candidate && (this.isLikelyId(candidate) || candidate.length >= 8)) {
return candidate;
}
}

// Return raw if it looks like an ID
return raw;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

🧩 Analysis chain

Deduplicate brief ID parsing across commands

extractBriefId is duplicated here and in context.command.ts. Extract to a shared util to prevent drift.

Proposed utility (apps/cli/src/utils/brief-input.util.ts):

export function extractBriefId(input: string): string | null { /* move shared logic */ }
export function isLikelyBriefId(value: string): boolean { /* move regexes */ }

Then replace method bodies here with calls to the util.

Find duplicates:


🏁 Script executed:

#!/bin/bash
rg -nP --type=ts 'extractBriefId\s*\(' apps/cli

Length of output: 393


Deduplicate brief‐ID parsing into a shared util

  • Both apps/cli/src/commands/export.command.ts and context.command.ts define identical extractBriefId (and use isLikelyId).
  • Move both functions into apps/cli/src/utils/brief-input.util.ts (exporting extractBriefId and isLikelyBriefId), then import and delegate in each command.
πŸ€– Prompt for AI Agents
In apps/cli/src/commands/export.command.ts around lines 238 to 284, the
extractBriefId (and its helper isLikelyId) are duplicated across
export.command.ts and context.command.ts; move the logic into a single shared
utility at apps/cli/src/utils/brief-input.util.ts exporting extractBriefId and
isLikelyBriefId, update both commands to import those functions and delegate to
them (replace local implementations), and adjust any references to isLikelyId to
use the new exported name; ensure the new util is exported with proper named
exports and update import paths in both command files so the project builds.

Comment on lines 246 to 251
task.subtasks.forEach((subtask) => {
const subIcon = STATUS_ICONS[subtask.status];
console.log(
` ${chalk.gray(`${task.id}.${subtask.id}`)} ${subIcon} ${chalk.gray(subtask.title)}`
` ${chalk.gray(String(subtask.id))} ${subIcon} ${chalk.gray(subtask.title)}`
);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Compact view: include parent id for subtask rows to avoid ambiguity.

Only showing subtask.id loses parent context (e.g., β€œ2” under multiple parents). Prefer β€œparent.subtask”.

-          console.log(
-            `  ${chalk.gray(String(subtask.id))} ${subIcon} ${chalk.gray(subtask.title)}`
-          );
+          console.log(
+            `  ${chalk.gray(`${task.id}.${subtask.id}`)} ${subIcon} ${chalk.gray(subtask.title)}`
+          );
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
task.subtasks.forEach((subtask) => {
const subIcon = STATUS_ICONS[subtask.status];
console.log(
` ${chalk.gray(`${task.id}.${subtask.id}`)} ${subIcon} ${chalk.gray(subtask.title)}`
` ${chalk.gray(String(subtask.id))} ${subIcon} ${chalk.gray(subtask.title)}`
);
});
task.subtasks.forEach((subtask) => {
const subIcon = STATUS_ICONS[subtask.status];
console.log(
` ${chalk.gray(`${task.id}.${subtask.id}`)} ${subIcon} ${chalk.gray(subtask.title)}`
);
});
πŸ€– Prompt for AI Agents
In apps/cli/src/commands/list.command.ts around lines 246 to 251, subtask rows
currently print only subtask.id which loses parent context; change the displayed
id to include the parent task id (e.g., use task.id + '.' + subtask.id) so rows
show "parent.subtask" (keep existing spacing/formatting and STATUS_ICONS usage).

Comment on lines +3 to +18
## 0.28.0-rc.2

### Minor Changes

- [#1273](https://github.com/eyaltoledano/claude-task-master/pull/1273) [`b43b7ce`](https://github.com/eyaltoledano/claude-task-master/commit/b43b7ce201625eee956fb2f8cd332f238bb78c21) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Add Codex CLI provider with OAuth authentication
- Added codex-cli provider for GPT-5 and GPT-5-Codex models (272K input / 128K output)
- OAuth-first authentication via `codex login` - no API key required
- Optional OPENAI_CODEX_API_KEY support
- Codebase analysis capabilities automatically enabled
- Command-specific settings and approval/sandbox modes

### Patch Changes

- [#1277](https://github.com/eyaltoledano/claude-task-master/pull/1277) [`7b5a7c4`](https://github.com/eyaltoledano/claude-task-master/commit/7b5a7c4495a68b782f7407fc5d0e0d3ae81f42f5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP connection errors caused by deprecated generateTaskFiles calls. Resolves "Cannot read properties of null (reading 'toString')" errors when using MCP tools for task management operations.

- [#1276](https://github.com/eyaltoledano/claude-task-master/pull/1276) [`caee040`](https://github.com/eyaltoledano/claude-task-master/commit/caee040907f856d31a660171c9e6d966f23c632e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add the final 0.28.0 section before shipping.

This PR is branded β€œRelease 0.28.0”, yet the changelog still stops at 0.28.0-rc.2. Please add the actual ## 0.28.0 entry (even if it rolls up the RC notes) so downstream tooling and humans see a tagged release note instead of the last RC.

πŸ€– Prompt for AI Agents
In CHANGELOG.md around lines 3 to 18, the changelog ends at 0.28.0-rc.2 but the
release is 0.28.0; add a new top-level section header "## 0.28.0" (immediately
above or replacing the RC heading as preferred) containing the final release
notes β€” you can roll up the RC notes or copy them under the new header β€” and
ensure formatting matches existing sections so downstream tooling recognizes the
tagged release.

Comment on lines +46 to +62
### Key Changes:
- **Unified AI Service**: Replaced separate generateText implementations with a single generateObjectService that handles structured data generation
- **JSON Mode Support**: Added proper JSON mode configuration for providers that support it (OpenAI, Anthropic, Google, Groq)
- **Schema Validation**: Integrated Zod schemas for all AI-generated content with automatic validation
- **Provider Compatibility**: Maintained compatibility with all existing providers while leveraging their native structured output capabilities
- **Improved Reliability**: Structured output generation reduces parsing errors and ensures consistent data formats

### Technical Improvements:
- Centralized provider configuration in `ai-providers-unified.js`
- Added `generateObject` support detection for each provider
- Implemented proper error handling for schema validation failures
- Maintained backward compatibility with existing prompt structures

### Bug Fixes:
- Fixed subtask ID numbering issue where AI was generating inconsistent IDs (101-105, 601-603) instead of sequential numbering (1, 2, 3...)
- Enhanced prompt instructions to enforce proper ID generation patterns
- Ensured subtasks display correctly as X.1, X.2, X.3 format
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Fix Markdown heading spacing.

### Key Changes, ### Technical Improvements, and ### Bug Fixes are missing blank lines around the headings, which is tripping markdownlint (MD022). Add an empty line both before and after each heading inside the bullet to quiet the lint and keep formatting consistent. Based on static analysis.

🧰 Tools
πŸͺ› markdownlint-cli2 (0.18.1)

46-46: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


53-53: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


59-59: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

πŸ€– Prompt for AI Agents
In CHANGELOG.md around lines 46 to 62, the Markdown headings "### Key Changes",
"### Technical Improvements", and "### Bug Fixes" are missing blank lines before
and after them which triggers MD022; add a single empty line both above and
below each of these headings (so there's a blank line separating the previous
bullet paragraph and the heading, and another blank line between the heading and
the following list) to satisfy markdownlint and preserve current bullet
formatting.

Comment on lines +237 to +252
private mapStatusToDatabase(
status: string
): Database['public']['Enums']['task_status'] {
switch (status) {
case 'pending':
return 'todo';
case 'in-progress':
case 'in_progress': // Accept both formats
return 'in_progress';
case 'done':
return 'done';
default:
throw new Error(
`Invalid task status: ${status}. Valid statuses are: pending, in-progress, done`
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Status filter/update throws for valid task statuses

TaskStatusSchema and our domain model allow values like review, blocked, etc., but mapStatusToDatabase only handles pending | in-progress | done. Any call to getTasks({ status: 'blocked' }) or updateTask(...,{ status: 'review' }) now throws Invalid task status, breaking supported flows. Align the schema and mapperβ€”either trim the schema to DB-supported states or extend the mapper with a translation strategyβ€”so we don’t reject legitimately requested statuses.

Comment on lines +404 to +418
const result = (await response.json()) as BulkTasksResponse;

if (result.failedCount > 0) {
const failedTasks = result.results
.filter((r) => !r.success)
.map((r) => `${r.externalId}: ${r.error}`)
.join(', ');
console.warn(
`Warning: ${result.failedCount} tasks failed to import: ${failedTasks}`
);
}

console.log(
`Successfully exported ${result.successCount} of ${result.totalTasks} tasks to brief ${briefId}`
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Surface partial failures to callers

When the bulk API reports failedCount > 0, we only log a warning and still return a success result (Line 175). That means the CLI (and any caller) will treat the export as fully successful, even though some tasks never made it into the brief. Users lose tasks silently.

Please propagate this state to the ExportResultβ€”either flip success to false (or add a partial‑success flag) and surface the failed task details in the returned payload so callers can react appropriately.

πŸ€– Prompt for AI Agents
In packages/tm-core/src/services/export.service.ts around lines 404 to 418, the
bulk API failure branch only logs a warning and still returns a successful
ExportResult; change the returned ExportResult to reflect partial failures by
setting success = false (or add a partialSuccess boolean) and include
failedCount and failed task details (externalId and error strings) on the result
object so callers can detect and surface partial failures; update the
ExportResult type/interface accordingly and adjust any callers/tests that assume
a pure success to handle the new failure/partial-success payload.

@eyaltoledano eyaltoledano self-requested a review October 7, 2025 14:33
eyaltoledano
eyaltoledano previously approved these changes Oct 7, 2025
Copy link
Owner

@eyaltoledano eyaltoledano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants