Skip to content

fix(session): keep todo state out of the system prompt - #209

Merged
filipeforattini merged 1 commit into
mainfrom
todo-reminder-context
Sep 11, 2026
Merged

fix(session): keep todo state out of the system prompt#209
filipeforattini merged 1 commit into
mainfrom
todo-reminder-context

Conversation

@filipeforattini

@filipeforattini filipeforattini commented Sep 11, 2026

Copy link
Copy Markdown

Problem

The legacy session loop (packages/redcode/src/session/prompt.ts) rebuilt the system array every step and included SessionTodo.context(...), which embeds the live task list. Every todowrite therefore changed the system prompt and invalidated the provider prompt-cache prefix for the next request. The goal, by contrast, was already re-rendered into the last user message via SessionReminders.apply, which keeps the system prompt stable.

Fix

  • SessionReminders.apply takes an optional todos list and appends SessionTodo.context(todos) to the last user message as a synthetic part, right after the goal reminder. Same text as before, so model behaviour is unchanged.
  • The loop reads todos.review once per step and passes the list to the reminders; the system array keeps only the static SessionTodo.guidance. A todo continuation carries its review into the step it starts instead of reading again.
  • .changeset/todo-reminder-context.md (@reddb-io/redcode: patch).

Out of scope on purpose: the daily date line and instruction/MCP/skills inputs are left as they are.

Test

New packages/redcode/test/session/prompt.test.ts case: the fake provider replies with a todowrite, then text, then a continuation. The test asserts the role-system messages of requests 2 and 3 are toEqual those of request 1, that the system prompt no longer contains the task-state block, and that request 2's last user message carries Current task state from storage: 0/1 completed with the task text.

  • Before the fix the test fails on the system equality with a diff showing No tracked tasks yet replaced by the task-state block; after the fix it passes.
  • One existing test that asserted the exact shape of the last user message was updated to the new shape (prompt text first, task-state reminder behind it).
  • test/session: 513 pass, 0 fail. bun run typecheck clean.

https://claude.ai/code/session_01KAcoL6wpgVEs2ebUrUGpHS


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

The legacy session loop rendered SessionTodo.context(...) into the system
array on every step. Each todowrite changed that text, so the request after
it sent a different system prompt and lost the provider's cached prefix.

The task list now rides the last user message as a synthetic reminder, the
same way the goal does in SessionReminders.apply, with the same text. The
system prompt keeps only the static todo guidance. The loop reviews the list
once per step: a todo continuation carries its review into the step it
starts instead of reading again.

Regression test drives the fake provider through a todowrite and asserts the
system messages of the following requests are identical to the first, while
the task state appears in the last user message of the next request.

Claude-Session: https://claude.ai/code/session_01KAcoL6wpgVEs2ebUrUGpHS
@filipeforattini
filipeforattini merged commit b300c3a into main Sep 11, 2026
12 of 15 checks passed
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