Skip to content

Ralph/feat/implement.ralph#1571

Merged
Crunchyman-ralph merged 61 commits intonextfrom
ralph/feat/implement.ralph
Jan 11, 2026
Merged

Ralph/feat/implement.ralph#1571
Crunchyman-ralph merged 61 commits intonextfrom
ralph/feat/implement.ralph

Conversation

@Crunchyman-ralph
Copy link
Collaborator

@Crunchyman-ralph Crunchyman-ralph commented Jan 10, 2026

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)

Note

Adds an autonomous loop workflow that executes one task per iteration with fresh Claude sessions.

  • New task-master loop CLI: Docker-sandboxed iterations, optional --tag, --progress-file, preset or custom prompts, iteration resolution, and result summary
  • Core module: LoopDomain/LoopService with preset resolution, prompt generation, progress logging, and <loop-complete>/<loop-blocked> detection
  • Built-in presets: default, test-coverage, linting, duplication, entropy; inlined content with tests and snapshots
  • CLI integration: command registered; unit and integration tests for options/validation and run flow
  • Docs: new Loop capability page and command reference updates; PRD for loop behavior; changeset added
  • Config/docs tweaks: main model set to claude-code: opus (32k); CLAUDE.md tool count corrected (42+); state currentTag switched to loop

Written by Cursor Bugbot for commit 5ff28c9. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Adds a new "loop" command to run Claude Code in iterative, sandboxed runs (Docker), with iterations, prompts, tag, JSON output, and progress-file support
    • Built-in presets: default, test-coverage, linting, duplication, entropy
    • Automatic completion/block detection via marker tags and progress tracking
  • Documentation

    • Full PRD, user docs, and command reference with examples, options, and presets
  • Tests

    • Extensive unit and integration tests for CLI, core domain, service, types, and presets

✏️ Tip: You can customize this high-level summary in your review settings.

Crunchyman-ralph and others added 30 commits January 8, 2026 19:29
Create the loop module with TypeScript type definitions for:
- LoopPreset: available preset loop prompts
- LoopConfig: configuration options for loop execution
- LoopIteration: result of a single loop iteration
- LoopResult: overall result of loop execution
- LoopCompletionMarker: marker for completion detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added types.spec.ts with compile-time type validation tests for all loop
module types: LoopPreset, LoopConfig, LoopIteration, LoopResult, and
LoopCompletionMarker. Task 1.2 was already implemented in 1.1.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Task 1.3 - interfaces were already implemented in types.ts during task 1.1.
Tests verified in types.spec.ts. TypeScript compilation passes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
LoopCompletionMarker was already implemented in types.ts from subtask 1.1.
Tests exist in types.spec.ts. tsc --noEmit passes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add presets module with:
- PRESET_NAMES constant array with all 5 preset names
- isValidPreset() type guard for validating preset names
- getPresetPath() for getting preset file paths
- loadPreset() async function for loading preset content

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bundled preset markdown files for loop module:
- default.md: standard task completion workflow
- test-coverage.md: test coverage improvement workflow
- linting.md: lint/type error fixing workflow
- duplication.md: code duplication refactoring workflow
- entropy.md: code smell cleanup workflow

Each preset includes @ file references, process steps,
completion markers (<loop-complete>), and single-task-per-iteration constraint.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add snapshot tests for all 5 preset files (default, test-coverage, linting, duplication, entropy)
- Add structure validation tests verifying <loop-complete> markers, @ file references, numbered steps
- Add default preset specific tests for <loop-blocked> marker
- Add content consistency tests for single-task-per-iteration constraint, progress file reference
- Update loadPreset tests to verify all presets load successfully

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create the base LoopProgressService with:
- ProgressEntry interface for tracking iteration data
- Constructor accepting projectRoot
- getDefaultProgressPath() method returning .taskmaster/loop-progress.txt

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements method to create a new progress file with header containing
timestamp, preset name, max iterations, and optional tag. Ensures parent
directory exists before writing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements method to append formatted progress entry lines to the
progress file. Entry format: [timestamp] Iteration N (Task ID): note
The task ID portion is optional.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- readProgress() reads file content, returns empty string if file missing
- exists() checks file accessibility using fs/promises access()
- Both methods handle errors gracefully without throwing
- Added 7 unit tests covering existing/missing file/directory scenarios

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…gration tests

Added exports for LoopProgressService class and ProgressEntry type to
loop/index.ts. Added barrel export tests and comprehensive integration
tests that verify the full workflow: initialize progress file, append
multiple entries, and read back content.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements LoopCompletionService with parseOutput() method that detects
<loop-complete> and <loop-blocked> markers in Claude output. Includes
comprehensive test coverage for all marker patterns, edge cases, and
case insensitivity.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ets module

- Add isFilePath() to detect file paths vs preset names
- Add resolvePrompt() to unify preset and custom file loading
- Add loadCustomPrompt() for custom prompt file loading
- Add PresetError class with typed error codes
- Add error handling for missing files and empty content
- Export new functions from loop module index
- Add comprehensive tests for new functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Presets are now embedded as string constants to avoid path resolution
issues during bundling. This eliminates filesystem reads for built-in
presets while maintaining the async API for backward compatibility.
Custom prompt files still use filesystem reads.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add integration tests to verify preset content is accessible without filesystem
dependencies, validating the inlined preset approach works in both development
and bundled distribution contexts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…e definitions

- Created PromptGenerationOptions interface for prompt generation config
- Added LoopPromptService class with dependency injection for LoopPresetService
- Included protected getPresetService() method for internal access
- Added unit tests for constructor and service instantiation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements iteration context generation with:
- Loop iteration count (e.g., "Loop Iteration 3 of 10")
- Progress file reference with @ syntax
- Tasks file reference
- Optional tag filter when config.tag is set

Includes 7 unit tests covering all scenarios.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add resolvePrompt() method to LoopPresetService for DI-compatible prompt resolution
- Implement generatePrompt() async method in LoopPromptService
- Combines context header with preset/custom prompt content using double newline separator
- Supports custom file prompts via optional readFile callback
- Add 8 unit tests for generatePrompt covering various scenarios

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… module barrel

- Create services/index.ts barrel file exporting all loop services
- Add LoopPromptService and PromptGenerationOptions to loop/index.ts
- Add barrel export tests for new exports in types.spec.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add snapshot tests for generated prompts from all 5 presets (default,
test-coverage, linting, duplication, entropy). Tests use real
LoopPresetService instead of mocks to verify actual prompt output.

Includes tests for:
- Snapshot tests for each preset with and without tag
- Context header validation with real presets
- Double newline separator verification
- Loop completion marker presence
- Iteration boundary handling (first, last, single, large counts)
- Tag handling (included/omitted)
- Custom progress file paths

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements task 7.1 - basic spawn mechanism with stdio capture:
- LoopExecutorService class that spawns Claude CLI with prompts
- Captures stdout/stderr output for completion marker detection
- Integrates LoopCompletionService for parsing output
- Process lifecycle management with stop() method
- Comprehensive unit tests with mocked child_process

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement LoopService class as the main orchestrator for loop execution.
The service constructor instantiates all sub-services with proper
dependency injection:
- LoopPresetService (standalone)
- LoopProgressService (receives projectRoot)
- LoopCompletionService (standalone)
- LoopPromptService (receives presetService)
- LoopExecutorService (receives completionService)

Includes run() method stub, stop() method, and comprehensive unit tests.
Exported from services/index.ts and loop/index.ts barrel files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The run() method implementation was already complete from task 8.1.
Verified: iteration tracking, completion detection, progress logging,
sleep between iterations, and proper finalStatus returns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added comprehensive tests for:
- stop() method: sets isRunning to false and calls executorService.stop()
- sleep() method: resolves after specified delay using fake timers
- run() graceful exit: respects isRunning flag and handles mid-loop stop

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement LoopDomain as the public API facade for loop operations:
- ConfigManager DI with projectRoot extraction
- Lazy LoopService instantiation via run()/stop()
- Config building with defaults (iterations=10, prompt='default', sleepSeconds=5)
- Preset operations: isPreset(), resolvePrompt(), getAvailablePresets()
- TasksDomain integration for checkAllTasksComplete()
- Unit tests covering all facade methods

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Crunchyman-ralph and others added 17 commits January 9, 2026 00:18
Adds 58 unit tests covering:
- Complete markers: position tests, various reasons
- Blocked markers: position tests, various reasons
- Case insensitivity: uppercase, mixed case
- Edge cases: empty input, long output, newlines
- Special characters: unicode, emoji, quotes
- Malformed markers: partial tags, mismatched tags
- extractCompletionReason method

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create apps/docs/capabilities/loop.mdx with Mintlify-compatible frontmatter,
overview section explaining the Ralph Wiggum pattern (credited to Jeffrey
Huntley, popularized by Matt Pocock), and basic usage examples for running
autonomous Claude Code loops.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents all five built-in loop presets: default, test-coverage, linting,
duplication, and entropy. Includes summary table, usage examples, detailed
workflow descriptions, and completion criteria for each preset.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document how to create custom prompts including required structure,
completion markers, file references with @ syntax, and best practices.
Add progress file section explaining format, usage, and how to
integrate with custom prompts for context continuity.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added loop_start and loop_presets to the standardTools array so they
are available when TASK_MASTER_TOOLS=standard is set.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updated .taskmaster/CLAUDE.md to reflect loop_start and loop_presets
being added to the standard tier:
- Standard tier now shows 16 tools (was 14)
- Standard adds line now includes loop_start and loop_presets
- Added Loop automation section to Essential MCP Tools

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add automated tests verifying loop tools (loop_start, loop_presets) are
correctly registered in MCP tool tiers. Tests verify:
- Loop tools registered in toolRegistry
- Loop tools included in standardTools (TASK_MASTER_TOOLS=standard)
- Loop tools excluded from coreTools (TASK_MASTER_TOOLS=core)
- All tool tier utility functions work correctly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reduce loop module complexity by merging 5 services into single LoopService:
- Merge LoopCompletionService, LoopProgressService, LoopPromptService,
  LoopExecutorService, LoopPresetService logic into LoopService
- Convert preset .md files to .ts files with exported constants
- Remove TasksDomain integration (setTasksDomain, checkAllTasksComplete)
- Remove LoopCompletionMarker type (inlined)
- Simplify presets/index.ts to minimal PRESETS record + helpers

Before: 6 service classes + 1 facade = 7 abstractions, ~1,754 lines
After: 1 service class + 1 facade + presets = 3 abstractions, ~500 lines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove loop_start and loop_presets MCP tools for now - can be added
back later when needed. Updates:
- Remove apps/mcp/src/tools/loop/ directory (4 files)
- Remove loop imports/exports from tool-registry.js
- Update standard tier from 16 to 14 tools
- Update .taskmaster/CLAUDE.md documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove options that weren't needed:
- CLI: Remove --status, --on-complete, --sleep options
- LoopConfig: Remove onComplete and status fields
- Keep --progress-file with default .taskmaster/progress.txt

Update progress file behavior:
- Keep init header on loop start
- Remove per-iteration appends (AI handles progress updates)
- Add final summary append when loop completes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Jan 10, 2026

🦋 Changeset detected

Latest commit: 5ff28c9

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 10, 2026

📝 Walkthrough

Walkthrough

📝 Walkthrough

Adds a new "loop" feature that runs Claude Code in iterative sandboxed tasks. Adds Loop domain/service/types/presets in tm-core, CLI command and scripts, progress tracking, presets, tests, docs, and wiring into TmCore and exports. Also updates some taskmaster config/metadata.

Changes

Cohort / File(s) Summary of changes (attention areas)
Core: loop module
packages/tm-core/src/modules/loop/*, packages/tm-core/src/modules/loop/presets/*, packages/tm-core/src/modules/loop/services/*, packages/tm-core/src/modules/loop/types.*, packages/tm-core/src/modules/loop/index.ts
New LoopDomain, LoopService, types, presets (default, test-coverage, linting, duplication, entropy), barrel exports, and many unit/integration tests. Review API shapes, async lifecycle (run/stop/isRunning), preset parsing (markers), and progress-file I/O.
Core: tm-core integration & tasks
packages/tm-core/src/tm-core.ts, packages/tm-core/src/modules/tasks/tasks-domain.ts, packages/tm-core/src/index.ts
Wire LoopDomain into TmCore and export loop types/values; added TasksDomain.getCount. Verify initialization ordering, constructor/initialize wiring, and public exports.
CLI
apps/cli/src/commands/loop.command.ts, apps/cli/src/commands/loop.command.spec.ts, apps/cli/src/command-registry.ts, apps/cli/src/index.ts, apps/cli/tests/integration/commands/loop.command.test.ts
New Loop CLI command, registration, option parsing, sandbox auth flow, iterations resolution, display logic, and tests. Check error handling, process exit paths, and integration with tmCore.loop APIs.
Docs & website
apps/docs/capabilities/loop.mdx, apps/docs/command-reference.mdx, apps/docs/docs.json, .taskmaster/docs/loop-prd.md
New PRD and user docs describing presets, progress file, markers, and CLI examples. Docs duplication noted in command-reference.
Taskmaster metadata & reports
.changeset/*, .taskmaster/config.json, .taskmaster/CLAUDE.md, .taskmaster/state.json, .taskmaster/loop-progress.txt, .taskmaster/reports/*.json
Add changeset, update model config (claude-code -> opus modelId), progress file, state.currentTag -> "loop", and complexity report. Model config change may affect runtime model selection.
Scripts & tooling
scripts/loop.sh, mcp-server/src/tools/tool-registry.js, tests/unit/mcp-server/tools/tool-registry.test.js
New shell helper implementing loop flow; minor doc count update in tool-registry and tests added. Review shell auth/wait logic and docker command composition.
Tests: integration & type checks
packages/tm-core/tests/integration/loop/*, packages/tm-core/src/modules/loop/*.spec.ts, packages/tm-core/src/modules/loop/types.spec.ts
Extensive test coverage added for presets, domain, service, CLI integration, and type-level guarantees. Ensure tests align with runtime behavior and I/O expectations.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI (task-master loop)
  participant TmCore as TmCore / LoopDomain
  participant LoopSvc as LoopService
  participant Docker as Docker Sandbox
  participant FS as Progress File (./.taskmaster/loop-progress.txt)

  CLI->>TmCore: resolveIterations / build config
  CLI->>TmCore: run(config)
  TmCore->>LoopSvc: start run(config)
  LoopSvc->>FS: init/append progress
  LoopSvc->>Docker: spawn Claude Code (per-iteration prompt)
  Docker-->>LoopSvc: iteration output (stdout)
  LoopSvc->>FS: append iteration result
  alt output contains <loop-complete> or <loop-blocked>
    LoopSvc->>TmCore: return final LoopResult (status)
    TmCore-->>CLI: present result
  else continue until iterations exhausted
    LoopSvc->>Docker: next iteration...
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • eyaltoledano
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Ralph/feat/implement.ralph' appears to be a branch name rather than a descriptive pull request title. It does not clearly communicate the main feature being implemented. Use a descriptive title that summarizes the primary change, such as 'Add Loop command for automated batch task execution' or 'Implement task-master loop workflow with Claude sandbox integration'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on February 9

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

- 1.1: Created loop module directory and types.ts. All types already implemented: LoopPreset, LoopConfig, LoopIteration, LoopResult, LoopCompletionMarker. index.ts barrel export also present.
- 1.2: Added types.spec.ts with compile-time type tests. LoopPreset/LoopConfig were already in types.ts from 1.1. tsc --noEmit passes. Native rollup module issue in env blocked vitest but types are correct.
- 1.3: LoopIteration and LoopResult interfaces already defined in types.ts (lines 38-63) from 1.1. Tests present in types.spec.ts (lines 69-129). tsc --noEmit passes. Marked done.
- 1.4: LoopCompletionMarker already defined in types.ts (lines 65-73) from 1.1. Tests in types.spec.ts (lines 131-149). tsc --noEmit passes. Marked done.
Copy link

Choose a reason for hiding this comment

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

Development notes committed to loop progress file

Medium Severity

The .taskmaster/loop-progress.txt file contains implementation notes about creating types.ts and spec files, but this file is intended to track context from actual loop command executions, not development progress. According to the changeset, users need to "delete this file between loops to not pollute the agent with bad context." Shipping this file with development notes will pollute the agent context for new users when they first run the loop command.

Fix in Cursor Fix in Web

"modelId": "haiku",
"maxTokens": 200000,
"modelId": "opus",
"maxTokens": 32000,
Copy link

Choose a reason for hiding this comment

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

Main model has fewer tokens than fallback model

Medium Severity

The main model configuration was changed from haiku with 200000 maxTokens to opus with only 32000 maxTokens. This results in the main model having half the token limit of the fallback model (which has 64000). This inverted relationship is unusual and the dramatic reduction from 200000 to 32000 tokens could cause response truncation. These changes appear unrelated to the loop feature being implemented and may be accidentally committed local development settings.

Fix in Cursor Fix in Web

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: 8

Caution

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

⚠️ Outside diff range comments (1)
mcp-server/src/tools/tool-registry.js (1)

120-133: Critical: Loop tools missing from registration and standardTools.

The test file expects loop_start and loop_presets to be:

  • Registered in toolRegistry (lines 19-27 of tool-registry.test.js)
  • Included in standardTools (lines 29-35)
  • Resulting in standardTools.length of 16 (line 52)

However, neither tool exists in the codebase. No loop tool files are present in mcp-server/src/tools/, and standardTools currently contains only 14 tools. The tests will fail until these loop tools are created and registered.

🤖 Fix all issues with AI agents
In @.taskmaster/config.json:
- Around line 5-6: Revert the manual edits to config.json that changed "modelId"
to "opus" and reduced "maxTokens" to 32000; instead set the main model via the
supported workflow by running the models MCP/CLI (e.g., use the provided
task-master models command to set the main model) so the change is recorded
through the proper tooling, and double-check whether the "maxTokens" reduction
from 200000 to 32000 is intentional—if it is not, restore the original maxTokens
value through the same models workflow rather than editing "maxTokens" directly
in config.json.

In @apps/cli/src/commands/loop.command.ts:
- Around line 129-151: If isJson is true and checkSandboxAuth() returns false,
do not invoke runInteractiveAuth() or start an interactive flow; instead
return/throw/log a non-interactive error so CI isn't blocked. Also after calling
tmCore.loop.runInteractiveAuth() in non-JSON mode, re-run
tmCore.loop.checkSandboxAuth() and only print the "✓ Auth complete" success (or
exit/throw non-zero) if the re-check returns true; if the re-check fails, print
an error and exit/throw accordingly. Reference: handleSandboxAuth,
tmCore.loop.checkSandboxAuth, and tmCore.loop.runInteractiveAuth.
- Around line 54-127: Normalize tag and make progressFile absolute at the start
of execute: derive a local normalizedTag = options.tag || 'master' right after
computing projectRoot and use normalizedTag everywhere (displayCommandHeader
call, config.tag, and tasks.getNext/getCount calls) instead of options.tag; for
progressFile resolve it against projectRoot (e.g., path.resolve(projectRoot,
options.progressFile || '.taskmaster/progress.txt')) and use that resolved value
when building config passed to this.tmCore.loop.run; ensure no other call still
references options.tag or the un-resolved progressFile.

In @packages/tm-core/src/modules/tasks/tasks-domain.ts:
- Around line 171-185: The parent task counting logic is inconsistent with
subtasks: change the task check in the loop over result.tasks to treat a missing
task.status as 'pending' the same way subtasks do; update the condition that
currently uses "task.status === status" to use "task.status === status ||
(status === 'pending' && !task.status)" so both tasks and task.subtasks are
counted the same way when status is absent, keeping the rest of the
count/subtask logic unchanged.

In @scripts/loop.sh:
- Around line 5-8: The script currently only checks for an empty $1 but doesn't
validate it as a positive integer; update the early validation to ensure $1 is a
numeric, positive integer (reject zero, negatives, and non-digits) before
proceeding, and if validation fails print the usage message and exit non-zero;
implement this by adding a numeric check (e.g. a regex test against $1 or using
POSIX-safe digit checks) around the existing echo/exit block so the loop code
that uses $1 only runs when $1 is a valid positive integer.

In @tests/unit/mcp-server/tools/tool-registry.test.js:
- Around line 17-44: Tests fail because the loop tools are missing: implement
modules that register loop_start and loop_presets so toolRegistry and
standardTools include them (or remove the tests if intentional). Add two modules
that export registration functions which add entries named "loop_start" and
"loop_presets" to toolRegistry (matching the expected keys) and ensure those
names are pushed into the standardTools array so its length reflects the added
tools (making standardTools.length match the test expectation of 16).
🧹 Nitpick comments (14)
packages/tm-core/src/tm-core.ts (1)

222-226: Consider cleanup for LoopDomain in close() method.

The close() method handles cleanup for TasksDomain but doesn't stop a potentially running loop. If a loop is in progress when close() is called, it may continue running.

♻️ Suggested enhancement
 async close(): Promise<void> {
+  if (this._loop) {
+    this._loop.stop();
+  }
   if (this._tasks) {
     await this._tasks.close();
   }
 }
packages/tm-core/tests/integration/loop/loop-tmcore-access.test.ts (1)

85-156: Consider testing the run() method integration.

The current tests cover static methods (isPreset, resolvePrompt, getAvailablePresets) and lifecycle queries (getIsRunning, stop), but don't exercise the main run() method. While this might be intentional due to the complexity of spawning Claude Code processes, consider adding at least one test that verifies the run() method accepts valid configuration.

Optional: Add run() method integration test
+	describe('Run Method Integration', () => {
+		it('should accept valid loop configuration', async () => {
+			tmCore = await createTmCore({ projectPath: testProjectDir });
+
+			// Verify run() method exists and accepts config
+			// Note: Not actually running the loop to avoid spawning processes in CI
+			expect(typeof tmCore.loop.run).toBe('function');
+		});
+	});

Note: A full integration test that actually spawns processes would be valuable but may require additional CI infrastructure.

packages/tm-core/src/modules/loop/services/loop.service.spec.ts (1)

45-48: Minor: Redundant mock restoration.

consoleSpy.mockRestore() on line 47 is redundant since vi.restoreAllMocks() on line 46 already restores all spies including consoleSpy.

Suggested cleanup
 	afterEach(() => {
 		vi.restoreAllMocks();
-		consoleSpy.mockRestore();
 	});
packages/tm-core/tests/integration/loop/loop-domain.test.ts (1)

165-170: Regex pattern may not match empty marker content.

The regex /<loop-complete>([^<]+)<\/loop-complete>/ requires at least one character inside the tags due to + quantifier. If any preset has an empty marker like <loop-complete></loop-complete>, this test would fail even though the marker exists.

Consider using * instead of + if empty content should be valid:

More permissive pattern
-				const match = content.match(/<loop-complete>([^<]+)<\/loop-complete>/);
+				const match = content.match(/<loop-complete>([^<]*)<\/loop-complete>/);
 				expect(match).toBeTruthy();
-				expect(match![1].length).toBeGreaterThan(0);
+				// Content inside marker exists (may be empty for some presets)
+				expect(match).not.toBeNull();
apps/cli/src/commands/loop.command.spec.ts (1)

328-332: Empty catch block could mask unexpected errors.

The empty catch block catches all errors including unexpected ones. Consider asserting the specific error or using a more targeted approach.

More explicit error handling in test
 			try {
 				await execute({});
 			} catch {
-				// Expected
+				// Expected - processExitSpy throws
 			}

Alternatively, you could use expect(...).rejects.toThrow() pattern if the execute function propagates the error.

packages/tm-core/src/modules/loop/services/loop.service.ts (2)

24-31: Duplicate PRESETS mapping violates DRY principle.

This PRESETS constant duplicates the same mapping already defined and exported from presets/index.ts. The service imports individual preset constants but creates its own mapping instead of importing the existing PRESETS export.

Import PRESETS from presets/index.ts
-import { DEFAULT_PRESET } from '../presets/default.js';
-import { DUPLICATION_PRESET } from '../presets/duplication.js';
-import { ENTROPY_PRESET } from '../presets/entropy.js';
-import { LINTING_PRESET } from '../presets/linting.js';
-import { TEST_COVERAGE_PRESET } from '../presets/test-coverage.js';
+import { PRESETS } from '../presets/index.js';
 import type {
 	LoopConfig,
 	LoopIteration,
 	LoopPreset,
 	LoopResult
 } from '../types.js';

 export interface LoopServiceOptions {
 	projectRoot: string;
 }

-/** Preset name to content mapping */
-const PRESETS: Record<LoopPreset, string> = {
-	default: DEFAULT_PRESET,
-	'test-coverage': TEST_COVERAGE_PRESET,
-	linting: LINTING_PRESET,
-	duplication: DUPLICATION_PRESET,
-	entropy: ENTROPY_PRESET
-};

91-93: Direct console.log usage violates coding guidelines.

Per coding guidelines: "Do not add direct console.log calls outside the logging utility - use the central log function instead."

Consider using the project's logging utility for iteration headers and output display.

packages/tm-core/src/modules/loop/loop-domain.spec.ts (2)

144-153: Assertion on preset order may be fragile.

The test asserts the exact order of presets returned by getAvailablePresets(). If Object.keys() order changes (though unlikely for string keys) or presets are reordered, this test would fail. Consider using toContain or toEqual(expect.arrayContaining([...])) for order-independent validation if order is not a contract.

Order-independent assertion alternative
 	it('should return array of all preset names', () => {
 		const presets = loopDomain.getAvailablePresets();
-		expect(presets).toEqual([
-			'default',
-			'test-coverage',
-			'linting',
-			'duplication',
-			'entropy'
-		]);
+		expect(presets).toHaveLength(5);
+		expect(presets).toEqual(
+			expect.arrayContaining([
+				'default',
+				'test-coverage',
+				'linting',
+				'duplication',
+				'entropy'
+			])
+		);
 	});

However, if the order is intentional and part of the API contract, the current assertion is appropriate.


161-165: Content assertion may be fragile.

The assertion expect(content).toContain('task-master') depends on the specific text in the default preset. If the preset content is refactored, this test could break even though the functionality is correct.

Consider asserting on structural properties (like presence of completion markers) rather than specific text content, which is already tested in line 164.

packages/tm-core/src/modules/loop/loop-domain.ts (2)

59-64: Silent catch block may hide unexpected errors.

The empty catch block swallows all errors from stop(), which could mask unexpected issues. Consider logging the error or being more specific about what errors are expected.

Add minimal error logging
 		if (this.loopService?.isRunning) {
 			try {
 				this.loopService.stop();
-			} catch {
+			} catch (e) {
 				// Ignore stop errors, proceed with new service
+				// Note: stop() is designed to be safe, errors here are unexpected
 			}
 		}

183-184: Consider using path.join for cross-platform compatibility.

The progress file path is constructed using string template with forward slash, which may cause issues on Windows. Consider using path.join() for cross-platform path construction per coding guidelines.

Use path.join for path construction

Add import at top:

import path from 'path';

Then update buildConfig:

 		progressFile:
-			partial.progressFile ?? `${this.projectRoot}/.taskmaster/progress.txt`,
+			partial.progressFile ?? path.join(this.projectRoot, '.taskmaster', 'progress.txt'),
apps/cli/src/commands/loop.command.ts (3)

30-52: Avoid baking preset names into CLI help text; prefer sourcing from tm-core (or a shared constant).
Hardcoding the preset list in the option description will drift as presets change. Consider importing a preset list/enum from @tm/core (if exposed) or a shared constant.


153-160: Make iteration validation strict (avoid parseInt accepting “1.5” as 1).
If you want “positive integer”, validate with Number() + Number.isInteger.

Proposed patch
@@
 	private validateIterations(iterations: string): void {
-		const parsed = parseInt(iterations, 10);
-		if (isNaN(parsed) || parsed < 1) {
+		const parsed = Number(iterations);
+		if (!Number.isInteger(parsed) || parsed < 1) {
 			throw new Error(
 				`Invalid iterations: ${iterations}. Must be a positive integer.`
 			);
 		}
 	}

162-179: Tighten statusMap typing to the known union.
Minor TS ergonomics: use Record<LoopResult['finalStatus'], string> so missing statuses become compile-time errors.

Comment on lines 54 to 127
private async execute(options: LoopCommandOptions): Promise<void> {
const prompt = options.prompt || 'default';
const progressFile = options.progressFile || '.taskmaster/progress.txt';

try {
const projectRoot = path.resolve(getProjectRoot(options.project));
this.tmCore = await createTmCore({ projectPath: projectRoot });

// Get pending task count for default preset iteration resolution
const pendingTaskCount =
prompt === 'default'
? await this.tmCore.tasks.getCount('pending', options.tag)
: undefined;

// Delegate iteration resolution logic to tm-core
const iterations = this.tmCore.loop.resolveIterations({
userIterations: options.iterations
? parseInt(options.iterations, 10)
: undefined,
preset: prompt,
pendingTaskCount
});

this.validateIterations(String(iterations));

if (!options.json) {
displayCommandHeader(this.tmCore, {
tag: options.tag || 'master',
storageType: this.tmCore.tasks.getStorageType()
});
}

this.handleSandboxAuth(options.json);

if (!options.json) {
console.log(chalk.cyan('Starting Task Master Loop...'));
console.log(chalk.dim(`Preset: ${prompt}`));
console.log(chalk.dim(`Max iterations: ${iterations}`));

// Show next task only for default preset (other presets don't use Task Master tasks)
if (prompt === 'default') {
const nextTask = await this.tmCore.tasks.getNext(options.tag);
if (nextTask) {
console.log(
chalk.white(
`Next task to work on: ${chalk.white(nextTask.id)} - ${nextTask.title}`
)
);
} else {
console.log(chalk.yellow('No pending tasks found'));
}
}
console.log();
}

const config: Partial<LoopConfig> = {
iterations,
prompt,
progressFile,
tag: options.tag
};

const result = await this.tmCore.loop.run(config);

if (options.json) {
console.log(JSON.stringify(result, null, 2));
} else {
this.displayResult(result);
}
} catch (error: unknown) {
displayError(error, { skipExit: true });
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check console.log vs display utility patterns in CLI commands
echo "=== Console.log usage in CLI commands ==="
rg -n --type=ts "console\.log\(" apps/cli/src/commands -C2

echo ""
echo "=== Display/logging utility imports in CLI commands ==="
rg -n --type=ts "from|import.*display|import.*log" apps/cli/src/commands/*.ts | head -40

Repository: eyaltoledano/claude-task-master

Length of output: 50387


🏁 Script executed:

#!/bin/bash
# Check tm-core loop module for API signatures
echo "=== Loop module API signatures ==="
find packages/tm-core/src/modules/loop -type f -name "*.ts" 2>/dev/null | head -10

echo ""
echo "=== LoopConfig interface ==="
rg -n "export interface LoopConfig|export type LoopConfig" packages/tm-core/src -A10

echo ""
echo "=== Loop.run signature ==="
rg -n "run\s*\(|async run" packages/tm-core/src/modules/loop -B2 -A5

Repository: eyaltoledano/claude-task-master

Length of output: 14156


🏁 Script executed:

#!/bin/bash
# Check resolveIterations and related methods
echo "=== resolveIterations method ==="
rg -n "resolveIterations" packages/tm-core/src -B2 -A8

echo ""
echo "=== Check getNext method signature ==="
rg -n "getNext\s*\(|async getNext" packages/tm-core/src -B2 -A5

Repository: eyaltoledano/claude-task-master

Length of output: 9386


🏁 Script executed:

#!/bin/bash
# Check progressFile usage in loop service
echo "=== progressFile usage in loop service ==="
rg -n "progressFile" packages/tm-core/src/modules/loop/services/loop.service.ts -B2 -A3

echo ""
echo "=== Path handling for progressFile ==="
rg -n "initProgressFile|progressFile.*path|resolve.*progress" packages/tm-core/src/modules/loop -B2 -A5

Repository: eyaltoledano/claude-task-master

Length of output: 3554


🏁 Script executed:

#!/bin/bash
# Check error handling pattern in other CLI commands
echo "=== process.exit vs process.exitCode in CLI commands ==="
rg -n "process\.exit|process\.exitCode" apps/cli/src/commands -B2 -A1 | head -60

Repository: eyaltoledano/claude-task-master

Length of output: 3442


🏁 Script executed:

#!/bin/bash
# Check how displayCommandHeader defaults tag
echo "=== displayCommandHeader usage and tag handling ==="
rg -n "displayCommandHeader" apps/cli/src -B2 -A2

Repository: eyaltoledano/claude-task-master

Length of output: 7393


Normalize tag at function entry, and resolve progressFile to absolute path.

  • options.tag is optional but used inconsistently: displayCommandHeader receives options.tag || 'master', while later calls pass options.tag directly. Normalize early to avoid tag mismatch in config and headers.
  • progressFile is passed as-is to tm-core; if relative, it resolves against CWD rather than projectRoot. Resolve to absolute path before passing to ensure consistent behavior.
Proposed patch
 	private async execute(options: LoopCommandOptions): Promise<void> {
-		const prompt = options.prompt || 'default';
-		const progressFile = options.progressFile || '.taskmaster/progress.txt';
+		const prompt = options.prompt ?? 'default';
+		const tag = options.tag ?? 'master';
 
 		try {
 			const projectRoot = path.resolve(getProjectRoot(options.project));
 			this.tmCore = await createTmCore({ projectPath: projectRoot });
 
+			const progressFileInput =
+				options.progressFile ?? '.taskmaster/progress.txt';
+			const progressFile = path.isAbsolute(progressFileInput)
+				? progressFileInput
+				: path.resolve(projectRoot, progressFileInput);
+
 			// Get pending task count for default preset iteration resolution
 			const pendingTaskCount =
 				prompt === 'default'
-					? await this.tmCore.tasks.getCount('pending', options.tag)
+					? await this.tmCore.tasks.getCount('pending', tag)
 					: undefined;
@@ -77,7 +87,7 @@
 			if (!options.json) {
 				displayCommandHeader(this.tmCore, {
-					tag: options.tag || 'master',
+					tag,
 					storageType: this.tmCore.tasks.getStorageType()
 				});
 			}
@@ -90,7 +100,7 @@
 				// Show next task only for default preset (other presets don't use Task Master tasks)
 				if (prompt === 'default') {
-					const nextTask = await this.tmCore.tasks.getNext(options.tag);
+					const nextTask = await this.tmCore.tasks.getNext(tag);
 					if (nextTask) {
@@ -108,7 +118,7 @@
 			const config: Partial<LoopConfig> = {
 				iterations,
 				prompt,
 				progressFile,
-				tag: options.tag
+				tag
 			};
🤖 Prompt for AI Agents
In @apps/cli/src/commands/loop.command.ts around lines 54 - 127, Normalize tag
and make progressFile absolute at the start of execute: derive a local
normalizedTag = options.tag || 'master' right after computing projectRoot and
use normalizedTag everywhere (displayCommandHeader call, config.tag, and
tasks.getNext/getCount calls) instead of options.tag; for progressFile resolve
it against projectRoot (e.g., path.resolve(projectRoot, options.progressFile ||
'.taskmaster/progress.txt')) and use that resolved value when building config
passed to this.tmCore.loop.run; ensure no other call still references
options.tag or the un-resolved progressFile.

Comment on lines +171 to +185
for (const task of result.tasks) {
// Count the task if it matches the status
if (task.status === status) {
count++;
}

// Count subtasks with matching status
if (task.subtasks && task.subtasks.length > 0) {
for (const subtask of task.subtasks) {
// For pending, also count subtasks without status (default to pending)
if (subtask.status === status || (status === 'pending' && !subtask.status)) {
count++;
}
}
}
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 handling of missing status between tasks and subtasks.

Line 173 counts parent tasks only when task.status === status, but line 181 treats subtasks without a status as 'pending' when status === 'pending'. This inconsistency means parent tasks without an explicit status field won't be counted as 'pending', while subtasks without status will be.

Based on the codebase pattern shown in scripts/modules/task-manager/list-tasks.js (lines 1018, 1047), both tasks and subtasks should default to 'pending' when status is missing.

🔧 Proposed fix to handle missing status consistently
 		let count = 0;
 		for (const task of result.tasks) {
-			// Count the task if it matches the status
-			if (task.status === status) {
+			// Count the task if it matches the status (default to 'pending' if missing)
+			const taskStatus = task.status || 'pending';
+			if (taskStatus === status) {
 				count++;
 			}
 
 			// Count subtasks with matching status
 			if (task.subtasks && task.subtasks.length > 0) {
 				for (const subtask of task.subtasks) {
-					// For pending, also count subtasks without status (default to pending)
-					if (subtask.status === status || (status === 'pending' && !subtask.status)) {
+					// Default to 'pending' if status is missing
+					const subtaskStatus = subtask.status || 'pending';
+					if (subtaskStatus === status) {
 						count++;
 					}
 				}
 			}
 		}
🤖 Prompt for AI Agents
In @packages/tm-core/src/modules/tasks/tasks-domain.ts around lines 171 - 185,
The parent task counting logic is inconsistent with subtasks: change the task
check in the loop over result.tasks to treat a missing task.status as 'pending'
the same way subtasks do; update the condition that currently uses "task.status
=== status" to use "task.status === status || (status === 'pending' &&
!task.status)" so both tasks and task.subtasks are counted the same way when
status is absent, keeping the rest of the count/subtask logic unchanged.

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

🤖 Fix all issues with AI agents
In @packages/tm-core/src/modules/loop/loop-domain.ts:
- Line 64: Replace the direct console.warn call in loop-domain.ts (the line that
currently reads console.warn('Failed to stop previous loop service:', error))
with the project's central logging utility (e.g., call logger.warn or log.warn)
and pass the error as structured context; import or reference the existing
central logger used across the codebase (the same logger used elsewhere) so the
message becomes something like logger.warn('Failed to stop previous loop
service', { error }) and remove the console import/usage.

In @packages/tm-core/src/modules/loop/services/loop.service.ts:
- Line 238: Replace the direct console.log call (if (output)
console.log(output);) with the central logging utility: use the project logger
(e.g., logger.info(output) or this.logger.debug(output) depending on context)
and ensure the appropriate logger is imported or injected into the LoopService
class; remove console.log and prefer an info/debug level so the message flows
through the central logging pipeline.
🧹 Nitpick comments (3)
apps/cli/src/commands/loop.command.spec.ts (1)

50-50: Consider stricter typing for mockTmCore.

Using any type reduces type safety. Consider defining a mock type or interface that matches the expected structure:

type MockTmCore = {
  loop: {
    run: Mock;
    checkSandboxAuth: Mock;
    runInteractiveAuth: Mock;
    resolveIterations: Mock;
  };
  tasks: {
    getStorageType: Mock;
    getNext: Mock;
    getCount: Mock;
  };
};
packages/tm-core/src/modules/loop/services/loop.service.ts (1)

5-7: Avoid node: prefix for core module imports.

Based on learnings, prefer bare imports for Node.js core modules instead of using the node: scheme.

♻️ Suggested refactor
-import { spawnSync } from 'node:child_process';
-import { appendFile, mkdir, readFile, writeFile } from 'node:fs/promises';
-import path from 'node:path';
+import { spawnSync } from 'child_process';
+import { appendFile, mkdir, readFile, writeFile } from 'fs/promises';
+import path from 'path';
packages/tm-core/src/modules/loop/loop-domain.ts (1)

6-6: Avoid node: prefix for core module imports.

Based on learnings, prefer bare imports for Node.js core modules instead of using the node: scheme.

♻️ Suggested refactor
-import path from 'node:path';
+import path from 'path';
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d99808 and edb7c58.

⛔ Files ignored due to path filters (1)
  • packages/tm-core/src/modules/loop/presets/__snapshots__/presets.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (9)
  • apps/cli/src/commands/loop.command.spec.ts
  • apps/cli/src/commands/loop.command.ts
  • packages/tm-core/src/index.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • packages/tm-core/src/modules/loop/presets/default.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • tests/unit/mcp-server/tools/tool-registry.test.js
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/unit/mcp-server/tools/tool-registry.test.js
  • packages/tm-core/src/modules/loop/presets/default.ts
  • apps/cli/src/commands/loop.command.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

TypeScript test files must achieve minimum code coverage thresholds: 80% lines/functions and 70% branches globally, 90% for utilities, and 85% for middleware; new features must meet or exceed these thresholds

Files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/index.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts}: Import and use specific getters from config-manager.js (e.g., getMainProvider(), getLogLevel(), getMainMaxTokens()) to access configuration values needed for application logic
Use isApiKeySet(providerName, session) from config-manager.js to check if a provider's key is available before potentially attempting an AI call
Do not add direct console.log calls outside the logging utility - use the central log function instead
Ensure silent mode is disabled in a finally block to prevent it from staying enabled
Do not access the global silentMode variable directly - use the exported silent mode control functions instead
Do not duplicate task ID formatting logic across modules - centralize formatting utilities
Use ContextGatherer class from utils/contextGatherer.js for AI-powered commands that need project context, supporting tasks, files, custom text, and project tree context
Use FuzzyTaskSearch class from utils/fuzzyTaskSearch.js for automatic task relevance detection with configurable search parameters
Use fuzzy search to supplement user-provided task IDs and display discovered task IDs to users for transparency
Do not replace explicit user task selections with fuzzy results - fuzzy search should supplement, not replace user selections
Use readJSON and writeJSON utilities for all JSON file operations instead of raw fs.readFileSync or fs.writeFileSync
Include error handling for JSON file operations and validate JSON structure after reading
Use path.join() for cross-platform path construction and path.resolve() for absolute paths, validating paths before file operations
Support both .env files and MCP session environment for environment variable resolution with fallbacks for missing values
Prefer updating the core function to accept an outputFormat parameter and check outputFormat === 'json' before displaying UI elements

Files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/index.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Import modules with .js extension even in TypeScript source files for ESM compatibility

Files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/index.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place package and app test files in packages/<package-name>/src/<module>/<file>.spec.ts or apps/<app-name>/src/<module>/<file>.spec.ts alongside source files

Files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
**/*.{spec,test}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{spec,test}.ts: Always use .ts for TypeScript tests, never .js
NEVER use async/await in test functions unless testing actual asynchronous operations; use synchronous top-level imports instead of dynamic await import()

Files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
apps/cli/**/*.{spec,test}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

In unit tests for apps/cli, mock tm-core responses but use real Commander/chalk/inquirer/other npm packages to test display logic

Files:

  • apps/cli/src/commands/loop.command.spec.ts
apps/cli/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

CLI (@tm/cli) should be a thin presentation layer that calls tm-core methods and displays results; handle only CLI-specific concerns like argument parsing, output formatting, and user prompts

Files:

  • apps/cli/src/commands/loop.command.spec.ts
packages/tm-core/**/*.{spec,test}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

In unit tests for @tm/core, mock only external I/O (Supabase, APIs, filesystem) and use real internal services

Files:

  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: assets/AGENTS.md:0-0
Timestamp: 2025-12-11T14:45:14.973Z
Learning: Applies to assets/**/CLAUDE.md : Update `CLAUDE.md` file with project-specific context, task summaries, and custom command examples for Claude Code integration
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/auth/config.ts:5-7
Timestamp: 2025-09-02T21:51:27.921Z
Learning: The user Crunchyman-ralph prefers not to use node: scheme imports (e.g., 'node:os', 'node:path') for Node.js core modules and considers suggestions to change bare imports to node: scheme as too nitpicky.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1069
File: .changeset/fix-tag-complexity-detection.md:0-0
Timestamp: 2025-08-02T15:33:22.656Z
Learning: For changeset files (.changeset/*.md), Crunchyman-ralph prefers to ignore formatting nitpicks about blank lines between frontmatter and descriptions, as he doesn't mind having them and wants to avoid such comments in future reviews.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1200
File: src/ai-providers/custom-sdk/grok-cli/language-model.js:96-100
Timestamp: 2025-09-19T16:06:42.182Z
Learning: The user Crunchyman-ralph prefers to keep environment variable names explicit (like GROK_CLI_API_KEY) rather than supporting multiple aliases, to avoid overlap and ensure clear separation between different CLI implementations.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/subpath-exports.test.ts:6-9
Timestamp: 2025-09-03T12:45:30.724Z
Learning: The user Crunchyman-ralph prefers to avoid overly nitpicky or detailed suggestions in code reviews, especially for test coverage of minor import paths. Focus on more substantial issues rather than comprehensive coverage of all possible edge cases.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1105
File: scripts/modules/supported-models.json:242-254
Timestamp: 2025-08-08T11:33:15.297Z
Learning: Preference: In scripts/modules/supported-models.json, the "name" field is optional. For OpenAI entries (e.g., "gpt-5"), Crunchyman-ralph prefers omitting "name" when the id is explicit enough; avoid nitpicks requesting a "name" in such cases.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1217
File: apps/cli/src/index.ts:16-21
Timestamp: 2025-09-18T16:35:35.147Z
Learning: The user Crunchyman-ralph considers suggestions to export types for better ergonomics (like exporting UpdateInfo type alongside related functions) as nitpicky and prefers not to implement such suggestions.
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to apps/cli/**/*.{spec,test}.ts : In unit tests for apps/cli, mock tm-core responses but use real Commander/chalk/inquirer/other npm packages to test display logic

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : When testing CLI commands built with Commander.js: test command action handlers directly rather than mocking the entire Commander chain; create simplified test-specific implementations of command handlers; explicitly handle all options including defaults and shorthand flags; include null/undefined checks for optional parameters; use fixtures for consistent sample data.

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to **/*.test.{js,ts} : Test new features with both legacy and tagged task data formats; verify tag resolution behavior; test migration compatibility; ensure pre-migration projects are handled correctly

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to packages/tm-core/**/*.{spec,test}.ts : In unit tests for tm/core, mock only external I/O (Supabase, APIs, filesystem) and use real internal services

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to **/*.test.ts : Unit tests must follow the describe/it pattern, use beforeEach for mock setup with jest.clearAllMocks(), include specific assertions with expect(), and test both success and error scenarios including edge cases

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to **/tests/integration/**/*.{spec,test}.ts : In integration tests, use real tm-core and mock only external boundaries (APIs, DB, filesystem)

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to package.json : package.json scripts must include: 'test', 'test:watch', 'test:coverage', 'test:unit', 'test:integration', 'test:e2e', and 'test:ci' commands for testing framework integration

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to apps/mcp/**/*.{spec,test}.ts : In unit tests for apps/mcp, mock tm-core responses but use real MCP framework to test response formatting

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to tests/e2e/**/*.test.js : Locate end-to-end tests in `tests/e2e/` directory. Test complete workflows from a user perspective, focus on CLI commands as users would use them.

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to tests/e2e/**/*.test.ts : End-to-end tests must test complete user workflows across multiple API endpoints in sequence, verify state changes between workflow steps, use extended timeouts (30000ms), and validate final outcomes without mocking business logic

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : When testing UI functions: mock console output and verify correct formatting; test conditional output logic; use `toContain()` or `toMatch()` rather than exact `toBe()` for strings with emojis or formatting; create separate tests for different behavior modes; test structure of formatted output rather than exact string matching.

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : For task file operations in tests: use test-specific file paths (e.g., 'test-tasks.json'); mock `readJSON` and `writeJSON` to avoid real file system interactions; verify file operations use correct paths; use different paths for each test; verify modifications on in-memory task objects passed to `writeJSON`.

Applied to files:

  • apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-09-26T19:05:47.555Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 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
📚 Learning: 2025-10-08T19:57:00.982Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1282
File: packages/tm-core/src/utils/index.ts:16-34
Timestamp: 2025-10-08T19:57:00.982Z
Learning: For the tm-core package in the eyaltoledano/claude-task-master repository, the team prefers a minimal, need-based export strategy in index files rather than exposing all internal utilities. Exports should only be added when functions are actually consumed by other packages in the monorepo.

Applied to files:

  • packages/tm-core/src/index.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to **/{utils,utilities}/**/*.{js,ts} : Export all utility functions explicitly in logical groups and include configuration constants from utility modules

Applied to files:

  • packages/tm-core/src/index.ts
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to **/tests/unit/packages/**/*.test.ts : Use isolated unit tests in `tests/unit/packages/<package-name>/` only when parallel placement isn't possible

Applied to files:

  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to tests/setup.ts : Create global test setup file that configures jest.setTimeout(10000), clears all mocks after each test with jest.clearAllMocks(), and initializes global test configuration

Applied to files:

  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to jest.config.js : Jest configuration must use ts-jest preset for TypeScript support, configure test environment as 'node', set roots to ['<rootDir>/src', '<rootDir>/tests'], and include testMatch patterns for both *.test.ts and *.spec.ts files with separate projects for unit, integration, and e2e tests

Applied to files:

  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to tests/fixtures/**/*.ts : Test fixture files must export reusable test data creators and constants (createTestUser, adminUser, invalidUser, etc.) for use across unit, integration, and e2e tests to ensure consistency

Applied to files:

  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Test files must be organized with unit tests separate from integration and e2e tests using project configuration in jest.config.js to maintain clear test separation and different timeout/environment settings

Applied to files:

  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : Do not import or instantiate real AI service clients. Create fully mocked versions that return predictable responses. Mock the entire module with controlled behavior.

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : Make async operations synchronous in tests. Mock async functions to return synchronous values when possible. Don't use real async/await or Promise resolution that might fail unpredictably.

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to **/*.integration.test.ts : Integration tests must use supertest for API endpoint testing, verify database state changes after operations, clean test data before each test, and include full request/response validation with expected HTTP status codes

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to tests/teardown.ts : Global teardown file must be created to handle cleanup after all tests complete and prevent worker process leaks

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
🧬 Code graph analysis (5)
packages/tm-core/src/modules/loop/services/loop.service.ts (3)
packages/tm-core/src/index.ts (4)
  • LoopConfig (153-153)
  • LoopResult (155-155)
  • LoopIteration (154-154)
  • LoopPreset (152-152)
packages/tm-core/src/modules/loop/types.ts (4)
  • LoopConfig (18-29)
  • LoopResult (50-59)
  • LoopIteration (34-45)
  • LoopPreset (8-13)
packages/tm-core/src/modules/loop/presets/index.ts (1)
  • PRESETS (16-22)
packages/tm-core/src/modules/loop/loop-domain.ts (3)
packages/tm-core/src/modules/loop/services/loop.service.ts (1)
  • LoopService (20-251)
packages/tm-core/src/modules/loop/types.ts (3)
  • LoopConfig (18-29)
  • LoopResult (50-59)
  • LoopPreset (8-13)
packages/tm-core/src/modules/loop/presets/index.ts (2)
  • getPreset (34-36)
  • PRESET_NAMES (27-27)
apps/cli/src/commands/loop.command.spec.ts (2)
apps/cli/src/commands/loop.command.ts (5)
  • LoopCommand (27-172)
  • validateIterations (139-146)
  • formatStatus (157-165)
  • displayResult (148-155)
  • execute (53-117)
packages/tm-core/src/modules/loop/types.ts (1)
  • LoopResult (50-59)
packages/tm-core/src/modules/loop/loop-domain.spec.ts (2)
packages/tm-core/src/modules/loop/loop-domain.ts (1)
  • LoopDomain (20-192)
packages/tm-core/src/modules/loop/types.ts (1)
  • LoopConfig (18-29)
packages/tm-core/src/modules/loop/services/loop.service.spec.ts (1)
packages/tm-core/src/modules/loop/services/loop.service.ts (5)
  • LoopServiceOptions (16-18)
  • LoopService (20-251)
  • parseCompletion (199-216)
  • isPreset (169-171)
  • buildContextHeader (184-189)
⏰ 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). (3)
  • GitHub Check: Test
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Mintlify Validation (taskmaster-49ce32d5) - vale-spellcheck
🔇 Additional comments (9)
apps/cli/src/commands/loop.command.spec.ts (6)

1-46: LGTM! Mock structure aligns with coding guidelines.

The mock setup correctly mocks @tm/core and utility functions while allowing real Commander usage, which aligns with the coding guideline to "mock tm-core responses but use real Commander/chalk/inquirer/other npm packages to test display logic."


106-131: LGTM! Comprehensive registration testing.

The tests properly verify command name, description, registration on parent program, and custom name support.


133-170: LGTM! Thorough option parsing coverage.

All CLI options are tested including defaults, short flags, and option presence. This ensures the Commander configuration is correct.


172-200: LGTM! Complete validation testing.

The tests cover all error cases (non-numeric, negative, zero) and the valid case, ensuring robust input validation.


202-248: LGTM! Display logic well-tested.

The tests properly verify status formatting for all cases and use toContain() for string assertions, which aligns with the coding guideline for testing formatted output.


250-425: Excellent comprehensive integration testing!

The execute integration tests provide exceptional coverage:

  • Core functionality: config passing, display, error handling
  • Default behavior: smart iteration defaults based on pending task count for default preset
  • Edge cases: explicit iterations override, non-default preset fallback to 10
  • Defensive testing: Line 369 verifies getCount is NOT called for non-default presets
  • Optional features: progressFile, tag, sandbox auth, next task display

This thorough testing approach will catch regressions effectively.

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

150-157: LGTM! Export structure follows established patterns.

The Loop module exports follow the same structure as other domain exports in this file, correctly separating type exports from value exports and using the .js extension for ESM compatibility.

packages/tm-core/src/modules/loop/services/loop.service.spec.ts (1)

1-703: LGTM! Excellent test coverage.

The test suite is comprehensive and follows best practices:

  • Mocks only external I/O boundaries (child_process, fs/promises) per guidelines
  • Tests constructor behavior, lifecycle, auth flows, iteration handling, and error scenarios
  • Properly suppresses console output during tests
  • Follows the describe/it pattern with beforeEach setup
packages/tm-core/src/modules/loop/loop-domain.spec.ts (1)

1-278: LGTM! Comprehensive domain test coverage.

The test suite thoroughly validates LoopDomain behavior including:

  • Configuration building with defaults and overrides
  • Preset recognition and resolution
  • Iteration resolution business logic
  • Lifecycle management

Follows best practices by mocking only external boundaries (ConfigManager) while testing real domain logic.

const output = (result.stdout || '') + (result.stderr || '');

// Print output to console (spawnSync with pipe captures but doesn't display)
if (output) console.log(output);
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 central logging utility instead of direct console.log.

Per coding guidelines, avoid direct console.log calls and use the central log function from the logging utility instead.

🤖 Prompt for AI Agents
In @packages/tm-core/src/modules/loop/services/loop.service.ts at line 238,
Replace the direct console.log call (if (output) console.log(output);) with the
central logging utility: use the project logger (e.g., logger.info(output) or
this.logger.debug(output) depending on context) and ensure the appropriate
logger is imported or injected into the LoopService class; remove console.log
and prefer an info/debug level so the message flows through the central logging
pipeline.

@Crunchyman-ralph Crunchyman-ralph force-pushed the ralph/feat/implement.ralph branch from edb7c58 to 5ff28c9 Compare January 11, 2026 00:37
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: 3

🤖 Fix all issues with AI agents
In @packages/tm-core/src/modules/loop/services/loop.service.ts:
- Around line 79-80: Replace the direct console.log calls in LoopService with
the class logger: remove the standalone console.log() and the console.log(`━━━
Iteration ${i} of ${config.iterations} ━━━`) and instead call
this.logger.info(...) (or logger.info if the class uses a logger property named
logger) with the same messages so logging goes through the central logging
utility; ensure you use the existing logger instance used elsewhere in
loop.service.ts (e.g., this.logger) and preserve the same message formatting.
- Around line 237-238: Replace the direct console.log call that prints the
variable output with the central logging utility used by this module: call the
existing logger instance on the LoopService (e.g., this.logger.info(output) or
logger.info(output)) instead of console.log; if no logger instance is present on
LoopService, import the project’s central logger and use logger.info with a
clear context message and the output variable.
🧹 Nitpick comments (6)
tests/unit/mcp-server/tools/tool-registry.test.js (4)

6-16: Consider reducing brittleness from deep relative import (optional).

The ../../../../mcp-server/... path is correct but fragile to directory reshuffles; if you have a stable internal alias/path mapping in this repo, using it would make tests less churny.


18-37: Avoid hardcoding tier counts in multiple places; prefer deriving from exports + use public accessor.

If the exact numbers (7/14) are meant to be a guardrail, centralize them; otherwise, key assertions should be based on exported arrays to avoid churn. Also prefer getToolRegistration() over direct toolRegistry[tool] indexing in tests.

Proposed refactor
 describe('tool-registry', () => {
+	const EXPECTED_CORE_COUNT = 7;
+	const EXPECTED_STANDARD_COUNT = 14;
+
 	describe('tool tier structure', () => {
 		it('should have exactly 7 core tools', () => {
-			expect(coreTools.length).toBe(7);
+			expect(coreTools.length).toBe(EXPECTED_CORE_COUNT);
 		});
 
 		it('should have exactly 14 standard tools', () => {
-			expect(standardTools.length).toBe(14);
+			expect(standardTools.length).toBe(EXPECTED_STANDARD_COUNT);
 		});
@@
 		it('should have all standardTools registered in toolRegistry', () => {
 			standardTools.forEach((tool) => {
-				expect(toolRegistry[tool]).toBeDefined();
+				expect(getToolRegistration(tool)).toBeDefined();
 			});
 		});
 	});

40-54: Strengthen low-signal assertions; cross-check counts against exports + available tools.

Right now getAvailableTools() is only validated as “an array”. You can make these tests both stronger and less duplicated by asserting consistency relationships.

Proposed refactor
 	describe('getAvailableTools', () => {
 		it('should return all registered tool names', () => {
 			const tools = getAvailableTools();
-			expect(Array.isArray(tools)).toBe(true);
+			expect(Array.isArray(tools)).toBe(true);
+			expect(tools).toEqual(expect.arrayContaining(standardTools));
 		});
 	});
 
 	describe('getToolCounts', () => {
 		it('should return correct counts', () => {
 			const counts = getToolCounts();
-			expect(counts.core).toBe(7);
-			expect(counts.standard).toBe(14);
-			expect(counts.total).toBeGreaterThanOrEqual(14);
+			expect(counts.core).toBe(coreTools.length);
+			expect(counts.standard).toBe(standardTools.length);
+			expect(counts.total).toBe(getAvailableTools().length);
+			expect(counts.total).toBeGreaterThanOrEqual(standardTools.length);
 		});
 	});

110-130: “TASK_MASTER_TOOLS behavior simulation” doesn’t exercise real behavior—consider renaming or relocating.

If filtering semantics live elsewhere (env parsing / tool selection), this block will give false confidence. Either rename it to reflect what it does (membership sanity checks) or move assertions to the module that actually implements TASK_MASTER_TOOLS filtering.

packages/tm-core/src/modules/loop/loop-domain.ts (1)

36-48: Consider reusing service instance for auth operations.

Both checkSandboxAuth() and runInteractiveAuth() create new LoopService instances. While not a significant issue, reusing a single instance would be more efficient.

♻️ Optional optimization
 export class LoopDomain {
 	private readonly logger = getLogger('LoopDomain');
 	private loopService: LoopService | null = null;
+	private authService: LoopService | null = null;
 	private readonly projectRoot: string;

 	constructor(configManager: ConfigManager) {
 		this.projectRoot = configManager.getProjectRoot();
 	}
 
+	private getAuthService(): LoopService {
+		if (!this.authService) {
+			this.authService = new LoopService({ projectRoot: this.projectRoot });
+		}
+		return this.authService;
+	}
+
 	// ========== Sandbox Auth Operations ==========

 	/**
 	 * Check if Docker sandbox auth is ready
 	 * @returns true if ready, false if auth needed
 	 */
 	checkSandboxAuth(): boolean {
-		const service = new LoopService({ projectRoot: this.projectRoot });
-		return service.checkSandboxAuth();
+		return this.getAuthService().checkSandboxAuth();
 	}

 	/**
 	 * Run Docker sandbox session for user authentication
 	 * Blocks until user completes auth
 	 */
 	runInteractiveAuth(): void {
-		const service = new LoopService({ projectRoot: this.projectRoot });
-		service.runInteractiveAuth();
+		this.getAuthService().runInteractiveAuth();
 	}
apps/cli/src/commands/loop.command.ts (1)

139-146: Validate iterations before passing to resolveIterations.

The validateIterations() method runs after resolveIterations() (line 76). This means invalid user input could be parsed and processed before validation occurs. Consider validating the raw user input earlier.

♻️ Suggested improvement

Move validation before calling resolveIterations:

 		try {
 			const projectRoot = path.resolve(getProjectRoot(options.project));
 			this.tmCore = await createTmCore({ projectPath: projectRoot });

+			// Validate user-provided iterations first
+			if (options.iterations) {
+				this.validateIterations(options.iterations);
+			}
+
 			// Get pending task count for default preset iteration resolution
 			const pendingTaskCount =
 				prompt === 'default'
 					? await this.tmCore.tasks.getCount('pending', options.tag)
 					: undefined;

 			// Delegate iteration resolution logic to tm-core
 			const iterations = this.tmCore.loop.resolveIterations({
 				userIterations: options.iterations
 					? parseInt(options.iterations, 10)
 					: undefined,
 				preset: prompt,
 				pendingTaskCount
 			});

-			this.validateIterations(String(iterations));
+			// Final sanity check (shouldn't fail if resolveIterations works correctly)
+			if (!Number.isInteger(iterations) || iterations < 1) {
+				throw new Error(`Invalid resolved iterations: ${iterations}`);
+			}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between edb7c58 and 5ff28c9.

⛔ Files ignored due to path filters (1)
  • packages/tm-core/src/modules/loop/presets/__snapshots__/presets.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (9)
  • apps/cli/src/commands/loop.command.spec.ts
  • apps/cli/src/commands/loop.command.ts
  • packages/tm-core/src/index.ts
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • packages/tm-core/src/modules/loop/presets/default.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • tests/unit/mcp-server/tools/tool-registry.test.js
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/tm-core/src/modules/loop/loop-domain.spec.ts
  • packages/tm-core/src/index.ts
  • packages/tm-core/src/modules/loop/presets/default.ts
  • apps/cli/src/commands/loop.command.spec.ts
  • packages/tm-core/src/modules/loop/services/loop.service.spec.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

TypeScript test files must achieve minimum code coverage thresholds: 80% lines/functions and 70% branches globally, 90% for utilities, and 85% for middleware; new features must meet or exceed these thresholds

Files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • apps/cli/src/commands/loop.command.ts
**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts}: Import and use specific getters from config-manager.js (e.g., getMainProvider(), getLogLevel(), getMainMaxTokens()) to access configuration values needed for application logic
Use isApiKeySet(providerName, session) from config-manager.js to check if a provider's key is available before potentially attempting an AI call
Do not add direct console.log calls outside the logging utility - use the central log function instead
Ensure silent mode is disabled in a finally block to prevent it from staying enabled
Do not access the global silentMode variable directly - use the exported silent mode control functions instead
Do not duplicate task ID formatting logic across modules - centralize formatting utilities
Use ContextGatherer class from utils/contextGatherer.js for AI-powered commands that need project context, supporting tasks, files, custom text, and project tree context
Use FuzzyTaskSearch class from utils/fuzzyTaskSearch.js for automatic task relevance detection with configurable search parameters
Use fuzzy search to supplement user-provided task IDs and display discovered task IDs to users for transparency
Do not replace explicit user task selections with fuzzy results - fuzzy search should supplement, not replace user selections
Use readJSON and writeJSON utilities for all JSON file operations instead of raw fs.readFileSync or fs.writeFileSync
Include error handling for JSON file operations and validate JSON structure after reading
Use path.join() for cross-platform path construction and path.resolve() for absolute paths, validating paths before file operations
Support both .env files and MCP session environment for environment variable resolution with fallbacks for missing values
Prefer updating the core function to accept an outputFormat parameter and check outputFormat === 'json' before displaying UI elements

Files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • tests/unit/mcp-server/tools/tool-registry.test.js
  • apps/cli/src/commands/loop.command.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Import modules with .js extension even in TypeScript source files for ESM compatibility

Files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • apps/cli/src/commands/loop.command.ts
**/*.js

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

**/*.js: Always use isSilentMode() function to check current silent mode status instead of directly accessing the global silentMode variable or global.silentMode
Use try/finally block pattern when wrapping core function calls with enableSilentMode/disableSilentMode to ensure silent mode is always restored, even if errors occur
For functions that need to handle both a passed silentMode parameter and check global state, check both the function parameter and global state: const isSilent = options.silentMode || (typeof options.silentMode === 'undefined' && isSilentMode())
Functions should accept their dependencies as parameters rather than using globals to promote testability and explicit dependency injection
Define callbacks as separate functions for easier testing rather than inline functions

Files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
tests/unit/**/*.js

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

Unit tests should be located in tests/unit/ and reflect the module structure with one test file per module

Files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
**/*.test.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/new_features.mdc)

**/*.test.{js,ts}: Follow the mock-first-then-import pattern for Jest mocking; use jest.spyOn() for spy functions; clear mocks between tests; verify mocks with the pattern described in tests.mdc
Test new features with both legacy and tagged task data formats; verify tag resolution behavior; test migration compatibility; ensure pre-migration projects are handled correctly

Files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
**/*.{js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

JavaScript test files using Jest must follow the same testing patterns as TypeScript files, include proper mocking of external dependencies, and achieve the same coverage thresholds

Files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
**/*.test.js

📄 CodeRabbit inference engine (.cursor/rules/tests.mdc)

**/*.test.js: Never use asynchronous operations in tests. Always mock tests properly based on the way the tested functions are defined and used.
Follow Jest test file structure: 1) Imports, 2) Mock setup before importing modules under test, 3) Import modules after mocks, 4) Set up spies on mocked modules, 5) Describe suite with descriptive name, 6) Setup/teardown hooks, 7) Grouped tests for related functionality, 8) Individual test cases with clear descriptions using Arrange-Act-Assert pattern.
When testing CLI commands built with Commander.js: test command action handlers directly rather than mocking the entire Commander chain; create simplified test-specific implementations of command handlers; explicitly handle all options including defaults and shorthand flags; include null/undefined checks for optional parameters; use fixtures for consistent sample data.
Use jest.mock() before any imports. Jest hoists mock calls to the top of the file. Always declare mocks before importing modules being tested. Use factory pattern for complex mocks that need access to other variables.
When testing ES modules with dynamic imports, use jest.unstable_mockModule() before await import(). Include __esModule: true in mock factories. Reset mock functions before dynamic import. Mock named and default exports as needed.
Mock file system operations using mock-fs library. Mock API calls by providing jest.fn() implementations that return expected structures. Mock environment variables in test setup.
When testing functions with callbacks: get the callback from mock's call arguments using mock.calls[index][argIndex]; execute it directly with test inputs; verify results match expectations.
For task file operations in tests: use test-specific file paths (e.g., 'test-tasks.json'); mock readJSON and writeJSON to avoid real file system interactions; verify file operations use correct paths; use different paths for each test; verify modifications on in-memory task objects passed t...

Files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
tests/unit/**/*.test.js

📄 CodeRabbit inference engine (.cursor/rules/tests.mdc)

Locate unit tests in tests/unit/ directory. Test individual functions and utilities in isolation, mock all external dependencies, keep tests small and focused.

Files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
apps/cli/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

CLI (@tm/cli) should be a thin presentation layer that calls tm-core methods and displays results; handle only CLI-specific concerns like argument parsing, output formatting, and user prompts

Files:

  • apps/cli/src/commands/loop.command.ts
🧠 Learnings (60)
📓 Common learnings
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: assets/AGENTS.md:0-0
Timestamp: 2025-12-11T14:45:14.973Z
Learning: Applies to assets/**/CLAUDE.md : Update `CLAUDE.md` file with project-specific context, task summaries, and custom command examples for Claude Code integration
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/auth/config.ts:5-7
Timestamp: 2025-09-02T21:51:27.921Z
Learning: The user Crunchyman-ralph prefers not to use node: scheme imports (e.g., 'node:os', 'node:path') for Node.js core modules and considers suggestions to change bare imports to node: scheme as too nitpicky.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1069
File: .changeset/fix-tag-complexity-detection.md:0-0
Timestamp: 2025-08-02T15:33:22.656Z
Learning: For changeset files (.changeset/*.md), Crunchyman-ralph prefers to ignore formatting nitpicks about blank lines between frontmatter and descriptions, as he doesn't mind having them and wants to avoid such comments in future reviews.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1200
File: src/ai-providers/custom-sdk/grok-cli/language-model.js:96-100
Timestamp: 2025-09-19T16:06:42.182Z
Learning: The user Crunchyman-ralph prefers to keep environment variable names explicit (like GROK_CLI_API_KEY) rather than supporting multiple aliases, to avoid overlap and ensure clear separation between different CLI implementations.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/subpath-exports.test.ts:6-9
Timestamp: 2025-09-03T12:45:30.724Z
Learning: The user Crunchyman-ralph prefers to avoid overly nitpicky or detailed suggestions in code reviews, especially for test coverage of minor import paths. Focus on more substantial issues rather than comprehensive coverage of all possible edge cases.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1105
File: scripts/modules/supported-models.json:242-254
Timestamp: 2025-08-08T11:33:15.297Z
Learning: Preference: In scripts/modules/supported-models.json, the "name" field is optional. For OpenAI entries (e.g., "gpt-5"), Crunchyman-ralph prefers omitting "name" when the id is explicit enough; avoid nitpicks requesting a "name" in such cases.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1217
File: apps/cli/src/index.ts:16-21
Timestamp: 2025-09-18T16:35:35.147Z
Learning: The user Crunchyman-ralph considers suggestions to export types for better ergonomics (like exporting UpdateInfo type alongside related functions) as nitpicky and prefers not to implement such suggestions.
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to **/*.{js,ts} : Do not add direct console.log calls outside the logging utility - use the central log function instead

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Do not wrap unified AI service calls (generateTextService, generateObjectService) in silent mode; their logging is handled internally

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T17:57:31.417Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-11-24T17:57:31.417Z
Learning: Applies to scripts/modules/task-manager/*.js, scripts/modules/commands.js : Centralize all LLM calls through `generateTextService` or `generateObjectService` from `ai-services-unified.js`

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to scripts/modules/task-manager/**/*.{js,ts} : 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

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-09-03T12:20:36.005Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/index.ts:56-57
Timestamp: 2025-09-03T12:20:36.005Z
Learning: The logger functionality in tm-core should only be available through the main package entry point (import { getLogger, createLogger, setGlobalLogger } from 'tm-core'), not as a separate subpath export like other modules such as auth or storage.

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T17:57:31.417Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-11-24T17:57:31.417Z
Learning: Applies to scripts/modules/task-manager/*.js, scripts/modules/commands.js : Do not initialize AI clients (Anthropic, Perplexity, etc.) directly within core logic or MCP direct functions; use the unified service layer instead

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Do not call or pass reportProgress in direct functions; use log.info() for internal progress reporting instead

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:02:49.782Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/telemetry.mdc:0-0
Timestamp: 2025-11-24T18:02:49.782Z
Learning: Applies to scripts/modules/task-manager/**/*.js : AI service functions in core logic (e.g., in scripts/modules/task-manager/) must call the appropriate AI service function (e.g., generateObjectService) and pass commandName and outputType in the params object

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
📚 Learning: 2025-11-24T17:57:31.417Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-11-24T17:57:31.417Z
Learning: Applies to scripts/modules/task-manager/*.js, scripts/modules/commands.js, scripts/modules/ai-services-unified.js : Do not import or call anything from deprecated AI service files (`ai-services.js`, `ai-client-factory.js`, `ai-client-utils.js`)

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:02:49.782Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/telemetry.mdc:0-0
Timestamp: 2025-11-24T18:02:49.782Z
Learning: Applies to scripts/modules/task-manager/**/*.js : Core logic functions with outputFormat parameter must check if outputFormat === 'text' and call displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli') from scripts/modules/ui.js when applicable

Applied to files:

  • packages/tm-core/src/modules/loop/services/loop.service.ts
  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Wrap core function calls and AI calls in try/catch blocks, log errors with appropriate severity and context, and return standardized error objects with code and message

Applied to files:

  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T17:57:31.417Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-11-24T17:57:31.417Z
Learning: Applies to scripts/modules/task-manager/*.js, scripts/modules/commands.js : Do not implement fallback or retry logic outside `ai-services-unified.js`; all fallback sequences and retry logic must be centralized in the unified service

Applied to files:

  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to **/{utils,utilities}/**/*.{js,ts} : Log detailed error information using the log utility in catch blocks for file operations

Applied to files:

  • packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/tools/index.js : Import and call tool registration functions in mcp-server/src/tools/index.js to register new MCP tools with the server

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to mcp-server/src/tools/index.js : Register MCP tools by importing and calling registration functions in `mcp-server/src/tools/index.js`

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T17:58:07.992Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-11-24T17:58:07.992Z
Learning: New MCP tools should be imported and registered in mcp-server/src/tools/index.js and tool definitions should be added to mcp.json

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/tools/*.js : Use camelCase with Tool suffix for tool registration functions (e.g., registerListTasksTool)

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : When testing CLI commands built with Commander.js: test command action handlers directly rather than mocking the entire Commander chain; create simplified test-specific implementations of command handlers; explicitly handle all options including defaults and shorthand flags; include null/undefined checks for optional parameters; use fixtures for consistent sample data.

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : For task file operations in tests: use test-specific file paths (e.g., 'test-tasks.json'); mock `readJSON` and `writeJSON` to avoid real file system interactions; verify file operations use correct paths; use different paths for each test; verify modifications on in-memory task objects passed to `writeJSON`.

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/tools/*.js : Include projectRoot as an optional parameter in tool definitions using zod schema

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to .cursor/mcp.json : Add new tool definitions to the tools array in `.cursor/mcp.json`

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to tests/unit/**/*.test.js : Locate unit tests in `tests/unit/` directory. Test individual functions and utilities in isolation, mock all external dependencies, keep tests small and focused.

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to mcp-server/src/tools/*.js : Create MCP tool definitions in `mcp-server/src/tools/` using kebab-case naming; use zod for parameter validation; make projectRoot optional as the HOF handles fallback; wrap execute method with `withNormalizedProjectRoot`

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/tools/*.js : Use snake_case for MCP tool names exposed to clients (e.g., list_tasks, set_task_status)

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:02:49.782Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/telemetry.mdc:0-0
Timestamp: 2025-11-24T18:02:49.782Z
Learning: Applies to mcp-server/src/tools/**/*.js : MCP tools in mcp-server/src/tools/ must call the corresponding direct function wrapper and pass the result object to handleApiResult(result, log) from mcp-server/src/tools/utils.js

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-10-11T22:32:11.922Z
Learnt from: rtmcrc
Repo: eyaltoledano/claude-task-master PR: 933
File: mcp-server/src/providers/agentllm-provider-tool-executor.js:289-329
Timestamp: 2025-10-11T22:32:11.922Z
Learning: In the Taskmaster codebase, when detecting agent-llm pending-interaction signals in tool results (agentllm-provider-tool-executor.js), the data is always stored in content[0], so there's no need to loop through all content items.

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to apps/mcp/**/*.{spec,test}.ts : In unit tests for apps/mcp, mock tm-core responses but use real MCP framework to test response formatting

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to **/*.test.{js,ts} : Test new features with both legacy and tagged task data formats; verify tag resolution behavior; test migration compatibility; ensure pre-migration projects are handled correctly

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to mcp-server/src/tools/**/*.{js,ts} : Use the withNormalizedProjectRoot Higher-Order Function to wrap tool execute methods, ensuring normalized project root is injected into args

Applied to files:

  • tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to apps/cli/src/**/*.{ts,tsx} : CLI (tm/cli) should be a thin presentation layer that calls tm-core methods and displays results; handle only CLI-specific concerns like argument parsing, output formatting, and user prompts

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to scripts/modules/commands.js : All new user-facing commands should be added to `commands.js` following Commander.js patterns for subcommand structure and consistent option naming

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to scripts/modules/**/*.{js,ts} : Implement tag resolution functions (getTasksForTag, setTasksForTag, getCurrentTag) that provide backward compatibility with legacy format and default to master tag

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to scripts/modules/*.js : Design core logic to work with both legacy (flat tasks array) and tagged task data formats; use tag resolution functions (getTasksForTag, setTasksForTag) for task data access; support silent migration during feature usage

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:04.644Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tags.mdc:0-0
Timestamp: 2025-11-24T18:02:04.644Z
Learning: Use consistent tag resolution across all commands to ensure predictable behavior

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:36.388Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-11-24T18:02:36.388Z
Learning: Applies to scripts/modules/task-manager.js : Extract tasks from PRD documents using AI within the current tag context (defaulting to "master"), providing clear prompts to guide AI task generation and validating/cleaning up AI-generated tasks

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:04.644Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tags.mdc:0-0
Timestamp: 2025-11-24T18:02:04.644Z
Learning: Applies to scripts/modules/task-manager/**/*.{js,mjs} : Pass context object `{ projectRoot, tag }` to all core functions that read or write tasks

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-07-18T08:29:52.384Z
Learnt from: mm-parthy
Repo: eyaltoledano/claude-task-master PR: 943
File: scripts/modules/task-manager/list-tasks.js:0-0
Timestamp: 2025-07-18T08:29:52.384Z
Learning: TODO comments about adding tag support to internal functions like readComplexityReport are obsolete in the boundary-first tag resolution pattern because report paths are already resolved at the CLI command boundary layer before reaching these functions.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:04.644Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tags.mdc:0-0
Timestamp: 2025-11-24T18:02:04.644Z
Learning: Every command that reads or writes tasks.json must be tag-aware and support the tagged task lists system

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to scripts/modules/*.js : Process large task lists efficiently; minimize file I/O operations per feature execution; cache tag resolution results when appropriate; avoid keeping all tag data in memory simultaneously

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : In MCP direct functions, support explicit tag specification and use tag resolution for task data operations; default to current tag when not specified

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to **/*.{js,ts} : Prefer updating the core function to accept an outputFormat parameter and check outputFormat === 'json' before displaying UI elements

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-26T20:50:40.810Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1451
File: apps/cli/src/ui/components/brand-banner.component.ts:42-44
Timestamp: 2025-11-26T20:50:40.810Z
Learning: In apps/cli/**/*.{ts,tsx}: Do not import or use isSilentMode() from the legacy scripts/modules/utils.js. isSilentMode is legacy code that will be removed during migration. The apps/cli package should use environment variables like TM_HIDE_BANNER for controlling output instead of legacy silent mode patterns.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : When testing UI functions: mock console output and verify correct formatting; test conditional output logic; use `toContain()` or `toMatch()` rather than exact `toBe()` for strings with emojis or formatting; create separate tests for different behavior modes; test structure of formatted output rather than exact string matching.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T17:58:07.992Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-11-24T17:58:07.992Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Direct functions (mcp-server/src/core/direct-functions/*Direct functions) should implement silent mode to prevent console logs from interfering with structured JSON responses required by MCP, using enableSilentMode/disableSilentMode around core function calls and passing the MCP logger via standard wrapper pattern

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:49.782Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/telemetry.mdc:0-0
Timestamp: 2025-11-24T18:02:49.782Z
Learning: Applies to scripts/modules/commands.js : CLI commands in scripts/modules/commands.js must call core logic functions with outputFormat: 'text' and pass commandNameFromContext and outputType: 'cli' in the context, allowing the core function to handle displayAiUsageSummary internally rather than calling it from the command itself

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to mcp-server/src/core/direct-functions/**/*.{js,ts} : In direct functions that call core functions, ensure console output from the core function is suppressed to avoid breaking MCP JSON responses

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/**/*.js : Do not log entire large data structures or sensitive information in direct functions and tools

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-02T21:51:27.921Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/auth/config.ts:5-7
Timestamp: 2025-09-02T21:51:27.921Z
Learning: The user Crunchyman-ralph prefers not to use node: scheme imports (e.g., 'node:os', 'node:path') for Node.js core modules and considers suggestions to change bare imports to node: scheme as too nitpicky.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-08-02T15:33:22.656Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1069
File: .changeset/fix-tag-complexity-detection.md:0-0
Timestamp: 2025-08-02T15:33:22.656Z
Learning: For changeset files (.changeset/*.md), Crunchyman-ralph prefers to ignore formatting nitpicks about blank lines between frontmatter and descriptions, as he doesn't mind having them and wants to avoid such comments in future reviews.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-03T12:45:30.724Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/subpath-exports.test.ts:6-9
Timestamp: 2025-09-03T12:45:30.724Z
Learning: The user Crunchyman-ralph prefers to avoid overly nitpicky or detailed suggestions in code reviews, especially for test coverage of minor import paths. Focus on more substantial issues rather than comprehensive coverage of all possible edge cases.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-03T12:16:15.866Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/package.json:13-64
Timestamp: 2025-09-03T12:16:15.866Z
Learning: For internal packages in the claude-task-master project, Crunchyman-ralph prefers pointing package.json "types" entries to src .ts files rather than dist .d.ts files for better developer experience (DX), as the packages are not being exported as SDKs.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-18T16:35:35.147Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1217
File: apps/cli/src/index.ts:16-21
Timestamp: 2025-09-18T16:35:35.147Z
Learning: The user Crunchyman-ralph considers suggestions to export types for better ergonomics (like exporting UpdateInfo type alongside related functions) as nitpicky and prefers not to implement such suggestions.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-26T19:28:42.612Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1252
File: packages/ai-sdk-provider-grok-cli/package.json:21-35
Timestamp: 2025-09-26T19:28:42.612Z
Learning: Crunchyman-ralph is concerned about preventing production failures when developers add external dependencies to internal packages but forget to add them to the root package.json in their tsdown bundling setup. He wants automated safety mechanisms to catch this during development or CI rather than discovering it in production.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-19T16:06:42.182Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1200
File: src/ai-providers/custom-sdk/grok-cli/language-model.js:96-100
Timestamp: 2025-09-19T16:06:42.182Z
Learning: The user Crunchyman-ralph prefers to keep environment variable names explicit (like GROK_CLI_API_KEY) rather than supporting multiple aliases, to avoid overlap and ensure clear separation between different CLI implementations.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-08-13T22:10:46.958Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-09T19:14:21.367Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1194
File: .github/workflows/ci.yml:21-21
Timestamp: 2025-09-09T19:14:21.367Z
Learning: User Crunchyman-ralph considers suggestions about adding safer default shell options (like bash -euo pipefail) to GitHub Actions workflows as too nitpicky and prefers not to implement them.

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T17:58:07.992Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-11-24T17:58:07.992Z
Learning: The Task Master CLI uses a modular architecture with distinct modules responsible for different aspects: commands.js (CLI command handling), task-manager.js (task data & core logic), dependency-manager.js (dependency management), ui.js (output formatting), ai-services-unified.js (unified AI service layer), config-manager.js (configuration management), utils.js (core utility functions), and mcp-server/ (MCP interface)

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:05:02.114Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: assets/.windsurfrules:0-0
Timestamp: 2025-11-24T18:05:02.114Z
Learning: Use the global CLI command `task-master` instead of `node scripts/dev.js` for all task management operations

Applied to files:

  • apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:00:32.617Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/glossary.mdc:0-0
Timestamp: 2025-11-24T18:00:32.617Z
Learning: Refer to commands.mdc for guidelines on implementing CLI commands using Commander.js

Applied to files:

  • apps/cli/src/commands/loop.command.ts
🧬 Code graph analysis (2)
packages/tm-core/src/modules/loop/loop-domain.ts (5)
packages/tm-core/src/index.ts (5)
  • LoopDomain (157-157)
  • LoopConfig (153-153)
  • LoopResult (155-155)
  • LoopPreset (152-152)
  • PRESET_NAMES (157-157)
packages/tm-core/src/modules/loop/index.ts (7)
  • LoopDomain (7-7)
  • LoopService (10-10)
  • LoopConfig (16-16)
  • LoopResult (18-18)
  • LoopPreset (15-15)
  • getPreset (25-25)
  • PRESET_NAMES (24-24)
packages/tm-core/src/modules/loop/services/loop.service.ts (1)
  • LoopService (20-251)
packages/tm-core/src/modules/loop/types.ts (3)
  • LoopConfig (18-29)
  • LoopResult (50-59)
  • LoopPreset (8-13)
packages/tm-core/src/modules/loop/presets/index.ts (2)
  • getPreset (34-36)
  • PRESET_NAMES (27-27)
tests/unit/mcp-server/tools/tool-registry.test.js (1)
mcp-server/src/tools/tool-registry.js (6)
  • getAvailableTools (139-141)
  • getToolCounts (147-153)
  • getToolCategories (159-167)
  • getToolRegistration (174-176)
  • isValidTool (183-185)
  • allTools (160-160)
⏰ 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). (2)
  • GitHub Check: Test
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (5)
tests/unit/mcp-server/tools/tool-registry.test.js (1)

56-108: These category/lookup validation tests look solid.

Good coverage of the public API surface (getToolCategories, getToolRegistration, isValidTool) without depending on tool ordering.

packages/tm-core/src/modules/loop/loop-domain.ts (2)

59-73: LGTM! Excellent error handling and cleanup logic.

The run() method properly handles the case where a loop is already running by attempting cleanup before starting a new loop. The try-catch with logger.warn ensures that cleanup failures don't block the new loop from starting.


150-173: LGTM! Clear business logic for iteration resolution.

The resolveIterations() method has well-documented logic with clear priority ordering: user-provided iterations take precedence, then preset-specific logic for the default preset, and finally a sensible default of 10 iterations.

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

53-117: LGTM! Well-structured command execution with proper delegation.

The execute() method follows the thin presentation layer pattern correctly:

  • Delegates iteration resolution to tm-core
  • Validates inputs appropriately
  • Uses display utilities where available
  • Handles errors with proper exit codes
  • Conditional logic for default preset is clean

The use of console.log with chalk for CLI output is acceptable for the presentation layer, though you could optionally extract these into display utility functions for consistency.


119-137: LGTM! Clear authentication flow with good user feedback.

The handleSandboxAuth() method provides clear status messages to guide users through the authentication process, with appropriate color coding for different states.

@Crunchyman-ralph Crunchyman-ralph merged commit c2d6c18 into next Jan 11, 2026
15 checks passed
@Crunchyman-ralph Crunchyman-ralph deleted the ralph/feat/implement.ralph branch January 11, 2026 00:47
@github-actions github-actions bot mentioned this pull request Jan 11, 2026
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.

1 participant