fix: enforce MEMORY.md header preservation and simplify /plan clear

Strengthen prompts to prevent LLM from overwriting the # Active Plan
header block. Include full header in Target Format template. Simplify
/plan clear to check ReadMemory instead of HasActivePlan so orphaned
MEMORY.md files can be cleared. Remove tg.expand() for default sizing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dj-oyu 2026-02-22 11:28:56 +09:00
parent 3168764369
commit 6134eb0ae3
3 changed files with 28 additions and 14 deletions

View file

@ -82,20 +82,22 @@ Your workspace is at: %s
3. **Memory & Plans** 3. **Memory & Plans**
- Use memory/MEMORY.md for structured plans. - Use memory/MEMORY.md for structured plans.
- NEVER remove or overwrite the header block (# Active Plan, > Task:, > Status:, > Phase:). The system parses these lines to track plan state.
- If Status is "interviewing": Ask clarifying questions. - If Status is "interviewing": Ask clarifying questions.
After each answer, use edit_file to save findings to ## Context in memory/MEMORY.md. After each answer, use edit_file to save findings to ## Context in memory/MEMORY.md.
When you have enough information, write ## Phase and ## Commands sections into MEMORY.md, then set Status to "executing". When you have enough information, add ## Phase sections with "- [ ]" checkbox steps, and ## Commands section below the header. Then change > Status: to "executing".
- If Status is "executing": Work through the current Phase's steps. - If Status is "executing": Work through the current Phase's steps.
Mark each [x] via edit_file. The system will auto-advance phases. Mark each "- [x]" via edit_file. The system will auto-advance phases.
- Plan format: - Plan format (header is written by the system do NOT delete it):
# Active Plan # Active Plan
> Task: <description> > Task: <description>
> Status: interviewing | executing > Status: interviewing | executing
> Phase: <current phase number> > Phase: <current phase number>
## Phase 1: <title> ## Phase 1: <title>
- [ ] Step 1 - [ ] Step 1
## Phase 2: <title>
- [ ] Step 2 - [ ] Step 2
## Phase 2: <title>
- [ ] Step 1
## Commands ## Commands
build: <build command> build: <build command>
test: <test command> test: <test command>

View file

@ -772,7 +772,7 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt
if agent.ContextBuilder.GetPlanStatus() == "interviewing" && agent.interviewStaleCount >= interviewStaleThreshold { if agent.ContextBuilder.GetPlanStatus() == "interviewing" && agent.interviewStaleCount >= interviewStaleThreshold {
messages = append(messages, providers.Message{ messages = append(messages, providers.Message{
Role: "user", Role: "user",
Content: "[System] You have been interviewing for several turns without updating memory/MEMORY.md. Please use edit_file now to save your findings to the ## Context section, or organize the plan into Phases if you have enough information.", Content: "[System] You have been interviewing for several turns without updating memory/MEMORY.md. Please use edit_file now to save your findings to the ## Context section, or organize the plan into ## Phase sections with `- [ ]` checkbox steps if you have enough information.",
}) })
} }
@ -968,7 +968,7 @@ func buildPlanReminder(planStatus string) (providers.Message, bool) {
case "interviewing": case "interviewing":
content = "[System] You are interviewing the user to build a plan. " + content = "[System] You are interviewing the user to build a plan. " +
"Ask clarifying questions and save findings to ## Context in memory/MEMORY.md using edit_file. " + "Ask clarifying questions and save findings to ## Context in memory/MEMORY.md using edit_file. " +
"When you have enough information, write ## Phases and ## Commands sections." "When you have enough information, write ## Phase sections with `- [ ]` checkbox steps, and ## Commands section."
case "review": case "review":
content = "[System] The plan is under review. " + content = "[System] The plan is under review. " +
"Wait for the user to approve or request changes. Do not proceed with execution." "Wait for the user to approve or request changes. Do not proceed with execution."
@ -2469,7 +2469,7 @@ func (al *AgentLoop) handlePlanCommand(args []string) (string, bool) {
sub := args[0] sub := args[0]
switch sub { switch sub {
case "clear": case "clear":
if !agent.ContextBuilder.HasActivePlan() { if agent.ContextBuilder.ReadMemory() == "" {
return "No active plan to clear.", true return "No active plan to clear.", true
} }
if err := agent.ContextBuilder.ClearMemory(); err != nil { if err := agent.ContextBuilder.ClearMemory(); err != nil {

View file

@ -449,23 +449,35 @@ func (ms *MemoryStore) GetInterviewContext() string {
sb.WriteString("- Tooling preferences (test framework, linter, formatter, CI)\n") sb.WriteString("- Tooling preferences (test framework, linter, formatter, CI)\n")
sb.WriteString("- Key commands the user already runs (build, test, deploy)\n") sb.WriteString("- Key commands the user already runs (build, test, deploy)\n")
sb.WriteString("\n### Rules\n") sb.WriteString("\n### Rules\n")
sb.WriteString("- NEVER remove or overwrite the header block (`# Active Plan`, `> Task:`, `> Status:`, `> Phase:` lines). The system parses these to track state.\n")
sb.WriteString("- After each answer, use edit_file to append findings to the ## Context section of memory/MEMORY.md.\n") sb.WriteString("- After each answer, use edit_file to append findings to the ## Context section of memory/MEMORY.md.\n")
sb.WriteString("- When you have enough information, use edit_file to write ## Phase, ## Commands, and ## Context sections into memory/MEMORY.md.\n") sb.WriteString("- When you have enough information, use edit_file to add ## Phase, ## Commands, and ## Context sections BELOW the header block.\n")
sb.WriteString("- Each step MUST use checkbox syntax: `- [ ] description`. The system parses checkboxes to track progress.\n")
sb.WriteString("- Organize into 2-5 phases with 3-5 steps each.\n") sb.WriteString("- Organize into 2-5 phases with 3-5 steps each.\n")
sb.WriteString("- After writing Phases, set Status to executing. The system will handle the rest.\n") sb.WriteString("- After writing Phases, change `> Status: interviewing` to `> Status: executing` via edit_file.\n")
sb.WriteString("\n### Target Format\n") sb.WriteString("\n### Target Format (MANDATORY — system parses this exact structure)\n")
sb.WriteString("```\n") sb.WriteString("\n")
sb.WriteString("# Active Plan\n")
sb.WriteString("> Task: <description>\n")
sb.WriteString("> WorkDir: <path>\n")
sb.WriteString("> Status: interviewing\n")
sb.WriteString("> Phase: 1\n")
sb.WriteString("\n")
sb.WriteString("## Phase 1: <title>\n") sb.WriteString("## Phase 1: <title>\n")
sb.WriteString("- [ ] Step\n") sb.WriteString("- [ ] Step description\n")
sb.WriteString("- [ ] Step description\n")
sb.WriteString("\n")
sb.WriteString("## Phase 2: <title>\n") sb.WriteString("## Phase 2: <title>\n")
sb.WriteString("- [ ] Step\n") sb.WriteString("- [ ] Step description\n")
sb.WriteString("- [ ] Step description\n")
sb.WriteString("\n")
sb.WriteString("## Commands\n") sb.WriteString("## Commands\n")
sb.WriteString("build: <project-specific build command>\n") sb.WriteString("build: <project-specific build command>\n")
sb.WriteString("test: <project-specific test command>\n") sb.WriteString("test: <project-specific test command>\n")
sb.WriteString("lint: <project-specific lint command>\n") sb.WriteString("lint: <project-specific lint command>\n")
sb.WriteString("\n")
sb.WriteString("## Context\n") sb.WriteString("## Context\n")
sb.WriteString("<collected requirements, decisions, environment>\n") sb.WriteString("<collected requirements, decisions, environment>\n")
sb.WriteString("```\n")
return sb.String() return sb.String()
} }