Skip to content

Conversation

@acoliver
Copy link
Collaborator

TLDR

Remove the priority field from the todo system to simplify the interface. The priority field served no meaningful purpose - it was not displayed in the UI panel, not used in continuation logic, and only affected secondary sort order in the text formatter.

Key Changes:

  • Removes TodoPriority enum and priority field from schemas
  • Updates sorting to use status first, then alphabetical by content
  • Removes priority-related statistics from tool metadata
  • Updates all tests and documentation

Dive Deeper

Why remove priority?

The issue (#1165) identified that priorities serve no purpose for todo_write/todo_read:

  • Priority badges ([HIGH], [MEDIUM], [LOW]) were displayed in the formatter but provided no actionable value
  • The UI panel did not display priorities
  • Continuation logic did not consider priority when selecting the next task
  • The complexity added cognitive overhead without benefits

Backward Compatibility

Zod's default parsing behavior strips unknown keys, so existing todo files with priority fields will load without errors - the field will simply be ignored. No migration is needed.

Sorting Behavior

After this change, todos are sorted by:

  1. Status first: in_progress > pending > completed
  2. Then alphabetically by content within each status group

This maintains deterministic ordering while simplifying the interface.

Files Modified

Core Implementation:

  • packages/core/src/tools/todo-schemas.ts - Removed TodoPriority enum and priority field
  • packages/core/src/tools/todo-write.ts - Removed priority from schema and statistics
  • packages/core/src/tools/todo-read.ts - Removed priority from description and statistics
  • packages/core/src/todo/todoFormatter.ts - Removed priority labels and sorting
  • packages/core/src/parsers/TextToolCallParser.ts - Removed priority normalization
  • packages/core/src/services/todo-reminder-service.ts - Removed priority reference
  • packages/core/src/core/client.ts - Removed priority from todo normalization

CLI Integration:

  • packages/cli/src/services/todo-continuation/todoContinuationService.ts - Updated comments
  • packages/cli/src/zed-integration/schema.ts - Removed priority from Zed ACP schema
  • packages/cli/src/zed-integration/zedIntegration.ts - Removed priority assignment

Tests (27 files):

  • Updated all todo-related tests to remove priority field from test data
  • Removed priority-specific test cases

Documentation:

  • docs/todo-system.md - Removed priority from parameter documentation

Reviewer Test Plan

  1. Pull and build the branch:
    ```bash
    git checkout issue1165
    npm install
    npm run build
    ```

  2. Run the test suite:
    ```bash
    npm run test
    npm run lint
    npm run typecheck
    ```

  3. Manual verification:
    ```bash
    node scripts/start.js

    In the chat, try creating a todo list:

    "Create a todo list with 3 tasks for building a web app"

    Verify the todos display correctly without priority badges

    ```

  4. Check backward compatibility - If you have existing todo files in `~/.llxprt/todos/`, they should still load correctly

Testing Matrix

Mac Windows Linux
npm run OK ? ?
npx ? ? ?
Docker ? ? ?
Podman ? - -
Seatbelt ? - -

Linked issues / bugs

Closes #1165

Remove the priority field from the todo system to simplify the interface.
The priority field served no meaningful purpose in the current
implementation and was not displayed in the UI panel or used in
continuation logic.

Changes:
- Remove TodoPriority enum and priority field from todo-schemas.ts
- Update todo-write.ts and todo-read.ts to remove priority from
  statistics and sorting (now sorts by status then alphabetically)
- Update todoFormatter.ts to remove priority labels and sorting
- Remove priority normalization from TextToolCallParser.ts
- Update all test files to remove priority references
- Update documentation in docs/todo-system.md

Backward compatibility is maintained - Zod strips unknown fields, so
existing todo files with priority will load without errors.

Closes #1165
@github-actions github-actions bot added the maintainer:e2e:ok Trusted contributor; maintainer-approved E2E run label Jan 25, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 25, 2026

Summary by CodeRabbit

  • Refactor
    • Removed the priority field across the todo system; selection now uses alphabetical/content order instead of priority.
    • Simplified display and ordering by removing priority labels and related metadata.
  • Documentation
    • Updated docs and descriptions to remove references to priority.
    • Adjusted UI placeholder text to remove the star symbol in the todo panel toggle.
  • Tests
    • Updated tests and fixtures to reflect the simplified todo shape and alphabetical ordering.

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

Walkthrough

This PR removes the priority field from Todo objects and replaces priority-based selection with alphabetical (content-based) ordering for pending todos; schemas, serializers, formatters, services, and tests are updated accordingly.

Changes

Cohort / File(s) Summary
Schemas & Types
packages/core/src/tools/todo-schemas.ts, packages/cli/src/zed-integration/schema.ts
Removed priority enum/type and priority field from Todo/PlanEntry schemas.
Selection & Service Logic
packages/core/src/tools/todo-read.ts, packages/core/src/tools/todo-write.ts, packages/cli/src/services/todo-continuation/todoContinuationService.ts
Replaced priority-based sorting/selection with alphabetical (content-based) selection; removed priority counters from stats.
Formatting & Serialization
packages/core/src/todo/todoFormatter.ts, packages/core/src/parsers/TextToolCallParser.ts, packages/core/src/core/client.ts, packages/cli/src/zed-integration/zedIntegration.ts, packages/core/src/services/todo-reminder-service.ts
Dropped priority from normalized/serialized todo objects; removed priority labels/ordering and related normalization code.
Tests — Services & Logic
packages/core/src/tools/todo-read.test.ts, packages/core/src/tools/todo-write.test.ts, packages/cli/src/services/todo-continuation/todoContinuationService.spec.ts, integration-tests/todo-continuation.e2e.test.js, packages/cli/src/integration-tests/todo-continuation.integration.test.ts
Updated expectations and fixtures to reflect alphabetical ordering and removed priority from test data.
Tests — Schemas & Tools
packages/core/src/tools/todo-schemas.test.ts, packages/core/src/tools/ToolFormatter.test.ts, packages/core/src/tools/todo-store.test.ts, packages/core/src/tools/todo-schemas.ts
Removed priority-related test cases and schema requirements; adjusted tool/schema tests to new shape.
UI & Hook Tests / Integration
packages/cli/src/ui/components/TodoPanel.responsive.test.tsx, packages/cli/src/ui/components/TodoPanel.semantic.test.tsx, packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx, packages/cli/src/ui/hooks/useGeminiStream.integration.test.tsx, packages/cli/src/ui/hooks/useTodoContinuation.spec.ts
Removed priority from fixtures used by UI/hook tests; test data shapes simplified.
Core Tests
packages/core/src/core/client.test.ts, packages/core/src/core/subagent.test.ts
Removed priority from mocked todo objects in tests.
Docs & Misc
docs/todo-system.md, packages/core/src/utils/parameterCoercion.test.ts, packages/core/src/tools/todoFormatter.test.ts
Documentation and parameter coercion tests updated to remove references to priority; minor placeholder text change in docs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰
I hopped through code with ears held high,
Priorities gone — an alphabet sky.
Tasks now line up, neat and bright,
Content-first, from left to right.
Hooray — simpler lists tonight!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: removing the priority field from the todo system. It accurately summarizes the primary objective of the PR.
Description check ✅ Passed The PR description is comprehensive and well-structured, including TLDR, detailed rationale, backward compatibility notes, sorting behavior explanation, files modified, and a thorough reviewer test plan.
Linked Issues check ✅ Passed The PR fully addresses the linked issue #1165 objective to remove the priority field from the todo system, eliminating the TodoPriority enum, updating schemas, removal logic, tests, and documentation as required.
Out of Scope Changes check ✅ Passed All changes are directly related to removing the priority field from the todo system. No out-of-scope modifications detected; updates to schemas, tests, sorting logic, formatters, and documentation are all aligned with the stated objective.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue1165

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link
Contributor

github-actions bot commented Jan 25, 2026

LLxprt PR Review – PR #1223

Issue Alignment

Ready. This PR directly addresses issue #1165 by removing the priority field from the todo system. The implementation is comprehensive:

  • Removes TodoPriority enum from packages/core/src/tools/todo-schemas.ts
  • Removes priority field from TodoSchema and updates required fields list
  • Updates todo_write and todo_read tools to remove priority from parameters and statistics
  • Changes continuation logic to select first task by LLM order instead of priority-based sorting
  • Updates formatter to remove priority badges [HIGH]/[MEDIUM]/[LOW]
  • Updates sorting to use status only, preserving original order within status groups
  • Documentation updated in docs/todo-system.md

Side Effects

  • Sorting behavior change: Tasks now sort alphabetically within status groups instead of by priority. This is intentional and documented in test changes.
  • Completed icon: The formatter's completed status icon changed from check to empty string. Verify this is intentional.
  • Backward compatibility: Zod's strict mode strips unknown fields, so existing API consumers sending priority will still work.

Code Quality

  • Clean, focused removals across 27 files
  • Good comments added explaining new behavior ("preserves LLM order")
  • No obvious bugs or error handling issues introduced
  • Consistent pattern for removing priority from all affected locations

Tests and Coverage

Coverage Impact: Increase (tests updated to reflect new behavior)

Tests are present and substantive:

  • Unit tests for schemas, tools, and services updated to remove priority assertions
  • E2E test renamed from "multiple active todos continuation priority" to "multiple active todos continuation alphabetical sorting" with updated assertions
  • Integration tests updated with new prompt format (removing priority from natural language input)
  • No mock theater detected—tests validate actual behavioral changes

Verdict

Ready. This PR is well-executed with comprehensive changes, proper test coverage, and clear documentation updates. The backward compatibility concern is mitigated by Zod's behavior. One minor note: verify the completed icon change from check to empty string is intentional before merging.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@docs/todo-system.md`:
- Line 46: The backticked placeholder "` Todo list updated`" contains a leading
space which violates MD038; update the markdown in docs/todo-system.md to remove
the leading space (change to "`Todo list updated`") or convert the placeholder
into normal prose, ensuring any reference to the todo_write tool calls still
reads correctly.

In `@packages/cli/src/services/todo-continuation/todoContinuationService.ts`:
- Around line 536-550: The alphabetical sort in findBestActiveTodo can throw
when todo.content is undefined; update the pendingTodos.sort call to compare
content in a null-safe way (e.g., use a default empty string or other fallback
for a.content and b.content before calling localeCompare) so malformed or
user-edited todos don't crash the continuation; ensure the comparator references
todo.content fallback consistently and keeps the same sort semantics for normal
entries.

In `@packages/core/src/todo/todoFormatter.ts`:
- Around line 21-25: The STATUS_ICONS map currently sets completed: '' which
causes the formatter to still emit a space prefix even when the icon is empty;
update the formatting logic that uses STATUS_ICONS (look for the function that
builds the line/label for a Todo using STATUS_ICONS and Todo['status']) to only
prepend the icon plus a trailing space when the icon string is non-empty (i.e.,
conditionally add `${icon} ` or nothing), ensuring alignment is preserved for
other statuses while avoiding a stray leading space for completed items.

In `@packages/core/src/tools/todo-read.test.ts`:
- Around line 159-161: The test currently uses a vacuous assertion
expect(result.llmContent).toContain('') which always passes; replace it with an
explicit check for the completed-task marker or completed task line used by the
todo renderer. Inspect how completed items are rendered in the codebase (the
todo formatter/parser used by the test) to find the exact symbol or text for
completed tasks, then change the assertion to something like
expect(result.llmContent).toContain('<completed-marker>') or use a regex/line
match (e.g., expect(result.llmContent).toMatch(/completed task text or marker/))
referencing result.llmContent in this test so the completed state is actually
validated instead of asserting an empty string.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84845e6 and b43d293.

📒 Files selected for processing (27)
  • docs/todo-system.md
  • integration-tests/todo-continuation.e2e.test.js
  • packages/cli/src/integration-tests/todo-continuation.integration.test.ts
  • packages/cli/src/services/todo-continuation/todoContinuationService.spec.ts
  • packages/cli/src/services/todo-continuation/todoContinuationService.ts
  • packages/cli/src/ui/components/TodoPanel.responsive.test.tsx
  • packages/cli/src/ui/components/TodoPanel.semantic.test.tsx
  • packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx
  • packages/cli/src/ui/hooks/useGeminiStream.integration.test.tsx
  • packages/cli/src/ui/hooks/useTodoContinuation.spec.ts
  • packages/cli/src/zed-integration/schema.ts
  • packages/cli/src/zed-integration/zedIntegration.ts
  • packages/core/src/core/client.test.ts
  • packages/core/src/core/client.ts
  • packages/core/src/core/subagent.test.ts
  • packages/core/src/parsers/TextToolCallParser.ts
  • packages/core/src/services/todo-reminder-service.ts
  • packages/core/src/todo/todoFormatter.ts
  • packages/core/src/tools/ToolFormatter.test.ts
  • packages/core/src/tools/todo-read.test.ts
  • packages/core/src/tools/todo-read.ts
  • packages/core/src/tools/todo-schemas.test.ts
  • packages/core/src/tools/todo-schemas.ts
  • packages/core/src/tools/todo-store.test.ts
  • packages/core/src/tools/todo-write.test.ts
  • packages/core/src/tools/todo-write.ts
  • packages/core/src/utils/parameterCoercion.test.ts
💤 Files with no reviewable changes (15)
  • packages/core/src/core/client.ts
  • packages/core/src/tools/todo-schemas.ts
  • packages/core/src/tools/todo-schemas.test.ts
  • packages/cli/src/ui/components/TodoPanel.responsive.test.tsx
  • packages/core/src/core/client.test.ts
  • packages/cli/src/zed-integration/zedIntegration.ts
  • packages/cli/src/ui/components/TodoPanel.semantic.test.tsx
  • packages/core/src/services/todo-reminder-service.ts
  • packages/core/src/parsers/TextToolCallParser.ts
  • packages/cli/src/zed-integration/schema.ts
  • packages/core/src/core/subagent.test.ts
  • packages/core/src/tools/todo-write.test.ts
  • packages/core/src/tools/todo-store.test.ts
  • packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx
  • packages/cli/src/ui/hooks/useGeminiStream.integration.test.tsx
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2026-01-14T08:00:48.375Z
Learnt from: sogoiii
Repo: vybestack/llxprt-code PR: 1124
File: packages/core/src/providers/ProviderManager.ts:869-884
Timestamp: 2026-01-14T08:00:48.375Z
Learning: In ProviderManager.getAvailableModels() in packages/core/src/providers/ProviderManager.ts, the supportedToolFormats field on IModel/HydratedModel is not actively used after the tool capabilities filtering feature was removed. It can be set to an empty array when constructing models from the registry fallback.

Applied to files:

  • packages/core/src/tools/ToolFormatter.test.ts
📚 Learning: 2025-11-25T16:56:18.980Z
Learnt from: CR
Repo: vybestack/llxprt-code PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T16:56:18.980Z
Learning: Before reporting a task as finished, run `node scripts/start.js --profile-load synthetic --prompt "write me a haiku"` from the repository root and ensure it succeeds (exit code 0)

Applied to files:

  • integration-tests/todo-continuation.e2e.test.js
📚 Learning: 2025-11-25T16:56:18.980Z
Learnt from: CR
Repo: vybestack/llxprt-code PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T16:56:18.980Z
Learning: Before reporting a task as finished, run `npm run typecheck` from the repository root and ensure it succeeds (exit code 0)

Applied to files:

  • integration-tests/todo-continuation.e2e.test.js
📚 Learning: 2025-11-25T16:56:18.980Z
Learnt from: CR
Repo: vybestack/llxprt-code PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T16:56:18.980Z
Learning: Before reporting a task as finished, run `npm run lint` from the repository root and ensure it succeeds (exit code 0)

Applied to files:

  • integration-tests/todo-continuation.e2e.test.js
📚 Learning: 2025-11-25T16:56:18.980Z
Learnt from: CR
Repo: vybestack/llxprt-code PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T16:56:18.980Z
Learning: Before reporting a task as finished, run `npm run test` from the repository root and ensure it succeeds (exit code 0)

Applied to files:

  • integration-tests/todo-continuation.e2e.test.js
🧬 Code graph analysis (4)
packages/core/src/tools/todo-read.test.ts (1)
packages/core/src/tools/todo-store.ts (1)
  • TodoStore (13-74)
integration-tests/todo-continuation.e2e.test.js (1)
integration-tests/test-helper.ts (3)
  • TestRig (243-1324)
  • printDebugInfo (78-104)
  • validateModelOutput (107-151)
packages/cli/src/integration-tests/todo-continuation.integration.test.ts (1)
packages/core/src/tools/todo-schemas.ts (1)
  • Todo (42-42)
packages/cli/src/ui/hooks/useTodoContinuation.spec.ts (1)
packages/core/src/tools/todo-schemas.ts (1)
  • Todo (42-42)
🪛 markdownlint-cli2 (0.18.1)
docs/todo-system.md

46-46: Spaces inside code span elements

(MD038, no-space-in-code)

⏰ Context from checks skipped due to timeout of 270000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Test (ubuntu-latest, 24.x)
  • GitHub Check: Test (macos-latest, 24.x)
  • GitHub Check: Test (windows-latest, 24.x)
  • GitHub Check: Slow E2E - Win
  • GitHub Check: E2E Test (Linux) - sandbox:docker
  • GitHub Check: E2E Test (Linux) - sandbox:none
  • GitHub Check: E2E Test (macOS)
🔇 Additional comments (19)
packages/cli/src/integration-tests/todo-continuation.integration.test.ts (1)

642-644: LGTM — malformed todo case still validates the schema guard.
Keeping the missing content case is sufficient for negative-path coverage after removing priority.

packages/cli/src/ui/hooks/useTodoContinuation.spec.ts (1)

519-531: Good malformed-data coverage.
The fixture now includes a pending todo missing content, which is a useful edge-case regression check for the continuation path.

packages/core/src/utils/parameterCoercion.test.ts (1)

228-247: LGTM: payload updated for new Todo shape.
Test data now matches the priority-free schema, which keeps coercion coverage accurate.

packages/cli/src/services/todo-continuation/todoContinuationService.spec.ts (1)

362-413: Tests align with alphabetical selection behavior.
Nice update to verify the first pending todo is chosen by content order when no in_progress items exist.

integration-tests/todo-continuation.e2e.test.js (3)

31-35: LGTM: basic flow updated for priority-free todos.
The scenario now reflects the new todo shape without priority metadata.


163-165: LGTM: auto-resume setup aligns with new input shape.
The updated creation prompt keeps the test consistent with the simplified todo schema.


394-450: Good coverage for alphabetical selection.
The multi-active scenario now correctly asserts the alphabetically first task is chosen.

docs/todo-system.md (1)

9-10: Docs align with priority removal.

Concise and consistent with the updated output semantics.

packages/core/src/tools/ToolFormatter.test.ts (1)

47-47: Schema expectations updated correctly.

Required fields now match the priority-free Todo schema.

packages/core/src/tools/todo-read.ts (3)

25-25: Updated description is accurate.

Reflects the simplified Todo shape.


104-107: Alphabetical selection for in-progress tasks looks good.


118-121: Alphabetical selection for pending tasks looks good.

packages/core/src/tools/todo-write.ts (3)

96-96: Required fields updated correctly.


251-254: Next-action selection by content is consistent with new behavior.


265-268: Pending-task selection by content is consistent with new behavior.

packages/core/src/tools/todo-read.test.ts (4)

19-43: Fixture updates match the new semantics.


70-72: Formatting assertions updated correctly.


85-91: Status ordering expectations look correct.


98-115: Alphabetical ordering test is clear and aligned.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


- The Todo panel is hidden immediately—no restart required.
- `todo_write` tool calls render the full structured todo list inline (status icons, priorities, subtasks, recent tool calls) instead of the ` Todo list updated` placeholder.
- `todo_write` tool calls render the full structured todo list inline (status icons, subtasks, recent tool calls) instead of the ` Todo list updated` placeholder.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix code span with leading space (MD038).

The backticked placeholder has a leading space, which violates markdownlint’s no-space-in-code rule and can render inconsistently. Prefer removing the space or describing it in prose.

📝 Suggested doc fix
-- `todo_write` tool calls render the full structured todo list inline (status icons, subtasks, recent tool calls) instead of the ` Todo list updated` placeholder.
+- `todo_write` tool calls render the full structured todo list inline (status icons, subtasks, recent tool calls) instead of the `Todo list updated` placeholder.
📝 Committable suggestion

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

Suggested change
- `todo_write` tool calls render the full structured todo list inline (status icons, subtasks, recent tool calls) instead of the ` Todo list updated` placeholder.
- `todo_write` tool calls render the full structured todo list inline (status icons, subtasks, recent tool calls) instead of the `Todo list updated` placeholder.
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

46-46: Spaces inside code span elements

(MD038, no-space-in-code)

🤖 Prompt for AI Agents
In `@docs/todo-system.md` at line 46, The backticked placeholder "` Todo list
updated`" contains a leading space which violates MD038; update the markdown in
docs/todo-system.md to remove the leading space (change to "`Todo list
updated`") or convert the placeholder into normal prose, ensuring any reference
to the todo_write tool calls still reads correctly.

Comment on lines 536 to 550
private findBestActiveTodo(todos: readonly Todo[]): Todo | undefined {
// Priority 1: Find in_progress todos (should be max 1)
// First: Find in_progress todos (should be max 1)
const inProgressTodos = todos.filter(
(todo) => todo.status === 'in_progress',
);
if (inProgressTodos.length > 0) {
return inProgressTodos[0];
}

// Priority 2: Find pending todos, prioritize by priority
// Second: Find pending todos, sort alphabetically by content
const pendingTodos = todos.filter((todo) => todo.status === 'pending');
if (pendingTodos.length > 0) {
// Sort by priority: high > medium > low
const priorityOrder: Record<string, number> = {
high: 3,
medium: 2,
low: 1,
};
pendingTodos.sort((a, b) => {
const aPriority = priorityOrder[a.priority || 'medium'] || 2;
const bPriority = priorityOrder[b.priority || 'medium'] || 2;
return bPriority - aPriority; // Descending order (high to low)
});
// Sort alphabetically by content
pendingTodos.sort((a, b) => a.content.localeCompare(b.content));
return pendingTodos[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard alphabetical sort against missing content.
localeCompare will throw if content is undefined; malformed or user-edited todo files could crash continuation. Consider a null-safe fallback when sorting.

🛠️ Proposed fix
-      pendingTodos.sort((a, b) => a.content.localeCompare(b.content));
+      pendingTodos.sort(
+        (a, b) => (a.content ?? '').localeCompare(b.content ?? ''),
+      );
📝 Committable suggestion

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

Suggested change
private findBestActiveTodo(todos: readonly Todo[]): Todo | undefined {
// Priority 1: Find in_progress todos (should be max 1)
// First: Find in_progress todos (should be max 1)
const inProgressTodos = todos.filter(
(todo) => todo.status === 'in_progress',
);
if (inProgressTodos.length > 0) {
return inProgressTodos[0];
}
// Priority 2: Find pending todos, prioritize by priority
// Second: Find pending todos, sort alphabetically by content
const pendingTodos = todos.filter((todo) => todo.status === 'pending');
if (pendingTodos.length > 0) {
// Sort by priority: high > medium > low
const priorityOrder: Record<string, number> = {
high: 3,
medium: 2,
low: 1,
};
pendingTodos.sort((a, b) => {
const aPriority = priorityOrder[a.priority || 'medium'] || 2;
const bPriority = priorityOrder[b.priority || 'medium'] || 2;
return bPriority - aPriority; // Descending order (high to low)
});
// Sort alphabetically by content
pendingTodos.sort((a, b) => a.content.localeCompare(b.content));
return pendingTodos[0];
private findBestActiveTodo(todos: readonly Todo[]): Todo | undefined {
// First: Find in_progress todos (should be max 1)
const inProgressTodos = todos.filter(
(todo) => todo.status === 'in_progress',
);
if (inProgressTodos.length > 0) {
return inProgressTodos[0];
}
// Second: Find pending todos, sort alphabetically by content
const pendingTodos = todos.filter((todo) => todo.status === 'pending');
if (pendingTodos.length > 0) {
// Sort alphabetically by content
pendingTodos.sort(
(a, b) => (a.content ?? '').localeCompare(b.content ?? ''),
);
return pendingTodos[0];
🤖 Prompt for AI Agents
In `@packages/cli/src/services/todo-continuation/todoContinuationService.ts`
around lines 536 - 550, The alphabetical sort in findBestActiveTodo can throw
when todo.content is undefined; update the pendingTodos.sort call to compare
content in a null-safe way (e.g., use a default empty string or other fallback
for a.content and b.content before calling localeCompare) so malformed or
user-edited todos don't crash the continuation; ensure the comparator references
todo.content fallback consistently and keeps the same sort semantics for normal
entries.

Comment on lines 21 to 25
const STATUS_ICONS: Record<Todo['status'], string> = {
in_progress: '→',
pending: '○',
completed: '✔',
};

const PRIORITY_LABELS: Record<Todo['priority'], string> = {
high: 'HIGH',
medium: 'MEDIUM',
low: 'LOW',
completed: '',
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid leading space when completed icon is empty.
With completed: '', the formatter now emits a leading space before content. A conditional prefix keeps output aligned without stray whitespace.

🛠️ Proposed fix
-  return `${marker} ${todo.content}${currentSuffix}`;
+  const prefix = marker ? `${marker} ` : '';
+  return `${prefix}${todo.content}${currentSuffix}`;

Also applies to: 139-143

🤖 Prompt for AI Agents
In `@packages/core/src/todo/todoFormatter.ts` around lines 21 - 25, The
STATUS_ICONS map currently sets completed: '' which causes the formatter to
still emit a space prefix even when the icon is empty; update the formatting
logic that uses STATUS_ICONS (look for the function that builds the line/label
for a Todo using STATUS_ICONS and Todo['status']) to only prepend the icon plus
a trailing space when the icon string is non-empty (i.e., conditionally add
`${icon} ` or nothing), ensuring alignment is preserved for other statuses while
avoiding a stray leading space for completed items.

Comment on lines +159 to +161
expect(result.llmContent).toContain('→'); // in_progress
expect(result.llmContent).toContain('○'); // pending
expect(result.llmContent).toContain(''); // completed
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid vacuous assertion for completed status.

toContain('') always passes and doesn’t validate output. Assert the completed line or marker explicitly.

✅ Suggested test fix
-      expect(result.llmContent).toContain(''); // completed
+      expect(result.llmContent).toContain(' Completed task'); // completed (no icon)
📝 Committable suggestion

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

Suggested change
expect(result.llmContent).toContain('→'); // in_progress
expect(result.llmContent).toContain('○'); // pending
expect(result.llmContent).toContain(''); // completed
expect(result.llmContent).toContain('→'); // in_progress
expect(result.llmContent).toContain('○'); // pending
expect(result.llmContent).toContain(' Completed task'); // completed (no icon)
🤖 Prompt for AI Agents
In `@packages/core/src/tools/todo-read.test.ts` around lines 159 - 161, The test
currently uses a vacuous assertion expect(result.llmContent).toContain('') which
always passes; replace it with an explicit check for the completed-task marker
or completed task line used by the todo renderer. Inspect how completed items
are rendered in the codebase (the todo formatter/parser used by the test) to
find the exact symbol or text for completed tasks, then change the assertion to
something like expect(result.llmContent).toContain('<completed-marker>') or use
a regex/line match (e.g., expect(result.llmContent).toMatch(/completed task text
or marker/)) referencing result.llmContent in this test so the completed state
is actually validated instead of asserting an empty string.

@acoliver
Copy link
Collaborator Author

@CodeRabbit explain the alphabetical sorting? You mean it changes the numeric task order and sorts them alphabetically or?

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 26, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the todoFormatter.ts to see the sorting implementation
cat packages/core/src/todo/todoFormatter.ts

Length of output: 5947


🏁 Script executed:

#!/bin/bash
# Read the todo-read.ts to see how tasks are selected
cat packages/core/src/tools/todo-read.ts

Length of output: 3844


🏁 Script executed:

#!/bin/bash
# Read the todoContinuationService to see continuation logic
cat packages/cli/src/services/todo-continuation/todoContinuationService.ts

Length of output: 16490


@acoliver The alphabetical sorting refers to sorting by the text content (description) of the todos, not by task IDs or any numeric ordering. Task IDs remain unchanged.

Here's how it works now:

Two-tier sorting:

  1. Primary sort: By status (in_progress → pending → completed) — unchanged
  2. Secondary sort: Changed from priority-based to alphabetical by content

Looking at the code in packages/core/src/todo/todoFormatter.ts:

const orderTodos = (todos: Todo[]): Todo[] =>
  [...todos].sort((a, b) => {
    const statusDiff = STATUS_ORDER[a.status] - STATUS_ORDER[b.status];
    if (statusDiff !== 0) {
      return statusDiff;
    }
    // Secondary sort: alphabetical by content
    return a.content.localeCompare(b.content);
  });

Example:

If you have these todos:

  • "Implement feature X" (pending)
  • "Add tests" (pending)
  • "Write docs" (in_progress)

They'll be displayed as:

  1. "Write docs" (in_progress) ← status takes priority
  2. "Add tests" (pending) ← alphabetically first within pending
  3. "Implement feature X" (pending) ← alphabetically second within pending

Previously: Within the same status, todos were ordered by priority (high → medium → low)
Now: Within the same status, todos are ordered alphabetically by their text content

This same alphabetical logic is used when selecting which task to continue in todo-read.ts and todoContinuationService.ts — the first task alphabetically (after sorting by status) is selected.

@acoliver
Copy link
Collaborator Author

@CodeRabbit -- expalin so before they showed in like numeric order and which as being done -- or at least I thought they did -- so if it adds 5 items to a todo they are now sorted alphabetically? with only the in progress at the top?

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 26, 2026

Tip

For best results, initiate chat on the files or code changes.

@acoliver The todos were never in numeric/ID order—you might have been seeing priority order and interpreted it as numeric! Here's what actually changed:

Before this PR:

  1. Primary sort: Status (in_progress → pending → completed)
  2. Secondary sort: Priority (high → medium → low)

After this PR:

  1. Primary sort: Status (in_progress → pending → completed) ← Still the same!
  2. Secondary sort: Alphabetical by content (A → Z)

Concrete Example:

If you add 5 items to a todo:

1. "Write tests" (pending)
2. "Add logging" (in_progress)
3. "Update docs" (pending)
4. "Fix bug" (completed)
5. "Code review" (in_progress)

Display order will be:

→ Add logging          (in_progress) ← alphabetically first within in_progress
→ Code review          (in_progress) ← alphabetically second within in_progress
○ Update docs          (pending)     ← alphabetically first within pending
○ Write tests          (pending)     ← alphabetically second within pending
  Fix bug              (completed)   ← only completed item

Key point: All in_progress tasks are always at the top (that hasn't changed). Within the in_progress group, they're now sorted A→Z by their content instead of by priority. Same for pending and completed groups.

The status-based grouping is preserved—you'll never see a pending task above an in_progress task!

Remove alphabetical content sorting from todo ordering - todos now
maintain the order the LLM added them within each status group
(in_progress first, then pending, then completed).

This ensures when an LLM creates a task list with a specific order,
the first pending task becomes the next task to work on, not
whichever one happens to be first alphabetically.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/core/src/tools/todo-write.ts`:
- Around line 248-263: determineNextAction currently preserves the input todos
order when selecting the first in-progress or pending task, but the PR expects
alphabetical ordering within each status group; update the selection logic in
determineNextAction to sort the filtered arrays (inProgressTasks and
pendingTasks) by task.content (case-insensitive) before taking the first
element, ensuring the same alphabetical tie-breaker used elsewhere (e.g.,
formatter/continuation) so next-task choice is consistent across components.
♻️ Duplicate comments (1)
packages/core/src/todo/todoFormatter.ts (1)

139-142: Avoid leading space when completed icon is empty.
Completed items still render with a leading space because the marker is '' and the formatter always prefixes "${marker} ". This was flagged earlier; consider the same conditional-prefix fix.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b43d293 and 282368e.

📒 Files selected for processing (3)
  • packages/core/src/todo/todoFormatter.ts
  • packages/core/src/tools/todo-read.ts
  • packages/core/src/tools/todo-write.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/tools/todo-read.ts
⏰ Context from checks skipped due to timeout of 270000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Test (macos-latest, 24.x)
  • GitHub Check: Test (ubuntu-latest, 24.x)
  • GitHub Check: Test (windows-latest, 24.x)
  • GitHub Check: E2E Test (macOS)
  • GitHub Check: E2E Test (Linux) - sandbox:none
  • GitHub Check: E2E Test (Linux) - sandbox:docker
🔇 Additional comments (2)
packages/core/src/tools/todo-write.ts (1)

96-96: Required fields update looks correct.

This aligns with removing priority from the schema.

packages/core/src/todo/todoFormatter.ts (1)

210-212: Confirm the intended secondary ordering within each status group.
The comparator now only uses status, so ordering within a status group follows original input order. The PR objectives mention alphabetical secondary ordering, while commit notes mention preserving LLM order. Please confirm the intended behavior and align docs/tests accordingly. If alphabetical is still desired, a secondary comparator will be needed.

Optional change if alphabetical ordering is intended
-const orderTodos = (todos: Todo[]): Todo[] =>
-  // Sort by status only, preserving original array order within each status group
-  [...todos].sort((a, b) => STATUS_ORDER[a.status] - STATUS_ORDER[b.status]);
+const orderTodos = (todos: Todo[]): Todo[] =>
+  [...todos].sort((a, b) => {
+    const statusDiff = STATUS_ORDER[a.status] - STATUS_ORDER[b.status];
+    if (statusDiff !== 0) return statusDiff;
+    return a.content.localeCompare(b.content);
+  });

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +248 to 263
// Check if any tasks are in progress - return first one (preserves LLM order)
const inProgressTasks = todos.filter((t) => t.status === 'in_progress');
if (inProgressTasks.length > 0) {
// Continue with highest priority in-progress task
const task = inProgressTasks.sort((a, b) => {
const priorityOrder = { high: 0, medium: 1, low: 2 };
return priorityOrder[a.priority] - priorityOrder[b.priority];
})[0];
const task = inProgressTasks[0];
return {
type: 'continue',
taskId: task.id,
taskContent: task.content,
};
}

// Check if any tasks are pending
// Check if any tasks are pending - return first one (preserves LLM order)
const pendingTasks = todos.filter((t) => t.status === 'pending');
if (pendingTasks.length > 0) {
// Start with highest priority pending task
const task = pendingTasks.sort((a, b) => {
const priorityOrder = { high: 0, medium: 1, low: 2 };
return priorityOrder[a.priority] - priorityOrder[b.priority];
})[0];
const task = pendingTasks[0];
return {
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

Align next-action ordering with the system-wide policy.

determineNextAction now preserves list order, but the PR objectives/summary describe alphabetical ordering within status groups. If other components (e.g., todo continuation or formatter) are using alphabetical ordering, this creates inconsistent “next task” selection. Please confirm the intended behavior and align all paths accordingly.

🛠️ If alphabetical ordering is intended, one possible fix
-    const inProgressTasks = todos.filter((t) => t.status === 'in_progress');
+    const inProgressTasks = todos.filter((t) => t.status === 'in_progress');
     if (inProgressTasks.length > 0) {
-      const task = inProgressTasks[0];
+      const task = inProgressTasks.sort((a, b) =>
+        a.content.localeCompare(b.content),
+      )[0];
       return {
         type: 'continue',
         taskId: task.id,
         taskContent: task.content,
       };
     }

     const pendingTasks = todos.filter((t) => t.status === 'pending');
     if (pendingTasks.length > 0) {
-      const task = pendingTasks[0];
+      const task = pendingTasks.sort((a, b) =>
+        a.content.localeCompare(b.content),
+      )[0];
       return {
         type: 'start',
         taskId: task.id,
         taskContent: task.content,
       };
     }
📝 Committable suggestion

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

Suggested change
// Check if any tasks are in progress - return first one (preserves LLM order)
const inProgressTasks = todos.filter((t) => t.status === 'in_progress');
if (inProgressTasks.length > 0) {
// Continue with highest priority in-progress task
const task = inProgressTasks.sort((a, b) => {
const priorityOrder = { high: 0, medium: 1, low: 2 };
return priorityOrder[a.priority] - priorityOrder[b.priority];
})[0];
const task = inProgressTasks[0];
return {
type: 'continue',
taskId: task.id,
taskContent: task.content,
};
}
// Check if any tasks are pending
// Check if any tasks are pending - return first one (preserves LLM order)
const pendingTasks = todos.filter((t) => t.status === 'pending');
if (pendingTasks.length > 0) {
// Start with highest priority pending task
const task = pendingTasks.sort((a, b) => {
const priorityOrder = { high: 0, medium: 1, low: 2 };
return priorityOrder[a.priority] - priorityOrder[b.priority];
})[0];
const task = pendingTasks[0];
return {
// Check if any tasks are in progress - return first one (preserves LLM order)
const inProgressTasks = todos.filter((t) => t.status === 'in_progress');
if (inProgressTasks.length > 0) {
const task = inProgressTasks.sort((a, b) =>
a.content.localeCompare(b.content),
)[0];
return {
type: 'continue',
taskId: task.id,
taskContent: task.content,
};
}
// Check if any tasks are pending - return first one (preserves LLM order)
const pendingTasks = todos.filter((t) => t.status === 'pending');
if (pendingTasks.length > 0) {
const task = pendingTasks.sort((a, b) =>
a.content.localeCompare(b.content),
)[0];
return {
🤖 Prompt for AI Agents
In `@packages/core/src/tools/todo-write.ts` around lines 248 - 263,
determineNextAction currently preserves the input todos order when selecting the
first in-progress or pending task, but the PR expects alphabetical ordering
within each status group; update the selection logic in determineNextAction to
sort the filtered arrays (inProgressTasks and pendingTasks) by task.content
(case-insensitive) before taking the first element, ensuring the same
alphabetical tie-breaker used elsewhere (e.g., formatter/continuation) so
next-task choice is consistent across components.

@acoliver
Copy link
Collaborator Author

Windows CI Flaky Test Note

The Windows test (windows-latest, 24.x) continues to fail with exit code 1 despite all tests passing:

```
Test Files 227 passed | 2 skipped (229)
Tests 3013 passed | 74 skipped (3108)
```

This appears to be a known flaky infrastructure issue unrelated to the code changes in this PR. All actual tests pass successfully on all platforms (Linux, macOS, Windows). The Windows job has been re-run multiple times with the same result.

Please consider manually merging or re-running the workflow.

@acoliver acoliver merged commit 17c4ac4 into main Jan 26, 2026
68 of 74 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer:e2e:ok Trusted contributor; maintainer-approved E2E run

Projects

None yet

Development

Successfully merging this pull request may close these issues.

remove "Priorities" from todolist

2 participants