pi-planning-with-files 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Session Catchup Script for planning-with-files (Pi Edition)
4
+
5
+ Session-agnostic scanning: finds the most recent planning file update across
6
+ ALL sessions, then collects all conversation from that point forward through
7
+ all subsequent sessions until now.
8
+
9
+ Usage: python3 session-catchup.py [project-path]
10
+ """
11
+
12
+ import json
13
+ import sys
14
+ import os
15
+ from pathlib import Path
16
+ from typing import List, Dict, Optional, Tuple
17
+
18
+ PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
19
+
20
+
21
+ def get_project_dir(project_path: str) -> Path:
22
+ """Convert project path to Pi's session storage path format."""
23
+ # expanduser handles ~, abspath handles relative paths
24
+ abs_path = os.path.abspath(os.path.expanduser(project_path))
25
+
26
+ # Pi treats paths as directory paths ending in /
27
+ if not abs_path.endswith('/'):
28
+ abs_path += '/'
29
+
30
+ # Pi session directory encoding:
31
+ # 1. Replace '/' with '-'
32
+ # 2. Wrap with '-' at start and end
33
+ # e.g. /Users/tmr/ -> -Users-tmr- -> --Users-tmr--
34
+ sanitized = abs_path.replace('/', '-')
35
+ sanitized = '-' + sanitized + '-'
36
+
37
+ # Pi session storage is in ~/.pi/agent/sessions/
38
+ return Path.home() / '.pi' / 'agent' / 'sessions' / sanitized
39
+
40
+
41
+ def get_sessions_sorted(project_dir: Path) -> List[Path]:
42
+ """Get all session files sorted by modification time (newest first)."""
43
+ if not project_dir.exists():
44
+ # Fallback: try without trailing slash doubling?
45
+ # No, let's stick to the observed pattern.
46
+ return []
47
+
48
+ sessions = list(project_dir.glob('*.jsonl'))
49
+ # Filter out any non-session files if any
50
+ sessions = [s for s in sessions if s.stat().st_size > 0]
51
+ return sorted(sessions, key=lambda p: p.stat().st_mtime, reverse=True)
52
+
53
+
54
+ def scan_for_planning_update(session_file: Path) -> Tuple[int, Optional[str]]:
55
+ """
56
+ Quickly scan a session file for planning file updates.
57
+ Returns (line_number, filename) of last update, or (-1, None) if none found.
58
+ """
59
+ last_update_line = -1
60
+ last_update_file = None
61
+
62
+ try:
63
+ with open(session_file, 'r') as f:
64
+ for line_num, line in enumerate(f):
65
+ # Quick pre-filter
66
+ line_lower = line.lower()
67
+ if '"write"' not in line_lower and '"edit"' not in line_lower:
68
+ continue
69
+
70
+ try:
71
+ entry = json.loads(line)
72
+ if entry.get('type') != 'message':
73
+ continue
74
+
75
+ message = entry.get('message', {})
76
+ if message.get('role') != 'assistant':
77
+ continue
78
+
79
+ content = message.get('content', [])
80
+ if not isinstance(content, list):
81
+ continue
82
+
83
+ for item in content:
84
+ if item.get('type') != 'toolCall':
85
+ continue
86
+
87
+ tool_name = item.get('name', '').lower()
88
+ if tool_name not in ('write', 'edit'):
89
+ continue
90
+
91
+ args = item.get('arguments', {})
92
+ # Pi tools usually use 'path'
93
+ file_path = args.get('path', args.get('file_path', ''))
94
+
95
+ for pf in PLANNING_FILES:
96
+ if file_path.endswith(pf):
97
+ last_update_line = line_num
98
+ last_update_file = pf
99
+ break
100
+ except json.JSONDecodeError:
101
+ continue
102
+ except Exception:
103
+ pass
104
+
105
+ return last_update_line, last_update_file
106
+
107
+
108
+ def extract_messages_from_session(session_file: Path, after_line: int = -1) -> List[Dict]:
109
+ """
110
+ Extract conversation messages from a session file.
111
+ If after_line >= 0, only extract messages after that line.
112
+ If after_line < 0, extract all messages.
113
+ """
114
+ result = []
115
+
116
+ # Use short UUID for display
117
+ session_id = session_file.stem.split('_')[-1][:8]
118
+
119
+ try:
120
+ with open(session_file, 'r') as f:
121
+ for line_num, line in enumerate(f):
122
+ if after_line >= 0 and line_num <= after_line:
123
+ continue
124
+
125
+ try:
126
+ entry = json.loads(line)
127
+ except json.JSONDecodeError:
128
+ continue
129
+
130
+ if entry.get('type') != 'message':
131
+ continue
132
+
133
+ message = entry.get('message', {})
134
+ role = message.get('role')
135
+ content_list = message.get('content', [])
136
+
137
+ if role == 'user':
138
+ text_content = ""
139
+ for item in content_list:
140
+ if item.get('type') == 'text':
141
+ text_content += item.get('text', '')
142
+
143
+ if text_content:
144
+ # Skip system/command messages if they look internal
145
+ # But generally show user commands
146
+ if len(text_content) > 0:
147
+ result.append({
148
+ 'role': 'user',
149
+ 'content': text_content,
150
+ 'line': line_num,
151
+ 'session': session_id
152
+ })
153
+
154
+ elif role == 'assistant':
155
+ text_content = ''
156
+ tool_uses = []
157
+
158
+ for item in content_list:
159
+ if item.get('type') == 'text':
160
+ text_content += item.get('text', '')
161
+ elif item.get('type') == 'toolCall':
162
+ tool_name = item.get('name', '')
163
+ args = item.get('arguments', {})
164
+
165
+ if tool_name == 'edit':
166
+ tool_uses.append(f"Edit: {args.get('path', 'unknown')}")
167
+ elif tool_name == 'write':
168
+ tool_uses.append(f"Write: {args.get('path', 'unknown')}")
169
+ elif tool_name == 'bash':
170
+ cmd = args.get('command', '')[:80]
171
+ tool_uses.append(f"Bash: {cmd}")
172
+ elif tool_name == 'read':
173
+ tool_uses.append(f"Read: {args.get('path', 'unknown')}")
174
+ else:
175
+ tool_uses.append(f"{tool_name}")
176
+
177
+ if text_content or tool_uses:
178
+ result.append({
179
+ 'role': 'assistant',
180
+ 'content': text_content[:600] if text_content else '',
181
+ 'tools': tool_uses,
182
+ 'line': line_num,
183
+ 'session': session_id
184
+ })
185
+ except Exception:
186
+ pass
187
+
188
+ return result
189
+
190
+
191
+ def main():
192
+ project_path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
193
+ project_dir = get_project_dir(project_path)
194
+
195
+ if not project_dir.exists():
196
+ # print(f"Session directory not found: {project_dir}")
197
+ return
198
+
199
+ sessions = get_sessions_sorted(project_dir)
200
+ if len(sessions) < 2:
201
+ return
202
+
203
+ # Skip the current session (most recently modified = index 0)
204
+ previous_sessions = sessions[1:]
205
+
206
+ # Find the most recent planning file update across ALL previous sessions
207
+ # Sessions are sorted newest first, so we scan in order
208
+ update_session = None
209
+ update_line = -1
210
+ update_file = None
211
+ update_session_idx = -1
212
+
213
+ for idx, session in enumerate(previous_sessions):
214
+ line, filename = scan_for_planning_update(session)
215
+ if line >= 0:
216
+ update_session = session
217
+ update_line = line
218
+ update_file = filename
219
+ update_session_idx = idx
220
+ break
221
+
222
+ if not update_session:
223
+ # No planning file updates found in any previous session
224
+ return
225
+
226
+ # Collect ALL messages from the update point forward, across all sessions
227
+ all_messages = []
228
+
229
+ # 1. Get messages from the session with the update (after the update line)
230
+ messages_from_update_session = extract_messages_from_session(update_session, after_line=update_line)
231
+ all_messages.extend(messages_from_update_session)
232
+
233
+ # 2. Get ALL messages from sessions between update_session and current
234
+ # These are sessions[1:update_session_idx] (newer than update_session)
235
+ intermediate_sessions = previous_sessions[:update_session_idx]
236
+
237
+ # Process from oldest to newest for correct chronological order
238
+ for session in reversed(intermediate_sessions):
239
+ messages = extract_messages_from_session(session, after_line=-1) # Get all messages
240
+ all_messages.extend(messages)
241
+
242
+ if not all_messages:
243
+ return
244
+
245
+ # Output catchup report
246
+ print("\n[planning-with-files] SESSION CATCHUP DETECTED")
247
+ print(f"Last planning update: {update_file} in session {update_session.stem.split('_')[-1][:8]}...")
248
+
249
+ sessions_covered = update_session_idx + 1
250
+ if sessions_covered > 1:
251
+ print(f"Scanning {sessions_covered} sessions for unsynced context")
252
+
253
+ print(f"Unsynced messages: {len(all_messages)}")
254
+
255
+ print("\n--- UNSYNCED CONTEXT ---")
256
+
257
+ # Show up to 100 messages
258
+ MAX_MESSAGES = 100
259
+ if len(all_messages) > MAX_MESSAGES:
260
+ print(f"(Showing last {MAX_MESSAGES} of {len(all_messages)} messages)\n")
261
+ messages_to_show = all_messages[-MAX_MESSAGES:]
262
+ else:
263
+ messages_to_show = all_messages
264
+
265
+ current_session = None
266
+ for msg in messages_to_show:
267
+ # Show session marker when it changes
268
+ if msg.get('session') != current_session:
269
+ current_session = msg.get('session')
270
+ print(f"\n[Session: {current_session}...]")
271
+
272
+ if msg['role'] == 'user':
273
+ print(f"USER: {msg['content'][:300]}")
274
+ else:
275
+ if msg.get('content'):
276
+ print(f"PI: {msg['content'][:300]}")
277
+ if msg.get('tools'):
278
+ print(f" Tools: {', '.join(msg['tools'][:4])}")
279
+
280
+ print("\n--- RECOMMENDED ---")
281
+ print("1. Run: git diff --stat")
282
+ print("2. Read: task_plan.md, progress.md, findings.md")
283
+ print("3. Update planning files based on above context")
284
+ print("4. Continue with task")
285
+
286
+
287
+ if __name__ == '__main__':
288
+ main()
@@ -0,0 +1,95 @@
1
+ # Findings & Decisions
2
+ <!--
3
+ WHAT: Your knowledge base for the task. Stores everything you discover and decide.
4
+ WHY: Context windows are limited. This file is your "external memory" - persistent and unlimited.
5
+ WHEN: Update after ANY discovery, especially after 2 view/browser/search operations (2-Action Rule).
6
+ -->
7
+
8
+ ## Requirements
9
+ <!--
10
+ WHAT: What the user asked for, broken down into specific requirements.
11
+ WHY: Keeps requirements visible so you don't forget what you're building.
12
+ WHEN: Fill this in during Phase 1 (Requirements & Discovery).
13
+ EXAMPLE:
14
+ - Command-line interface
15
+ - Add tasks
16
+ - List all tasks
17
+ - Delete tasks
18
+ - Python implementation
19
+ -->
20
+ <!-- Captured from user request -->
21
+ -
22
+
23
+ ## Research Findings
24
+ <!--
25
+ WHAT: Key discoveries from web searches, documentation reading, or exploration.
26
+ WHY: Multimodal content (images, browser results) doesn't persist. Write it down immediately.
27
+ WHEN: After EVERY 2 view/browser/search operations, update this section (2-Action Rule).
28
+ EXAMPLE:
29
+ - Python's argparse module supports subcommands for clean CLI design
30
+ - JSON module handles file persistence easily
31
+ - Standard pattern: python script.py <command> [args]
32
+ -->
33
+ <!-- Key discoveries during exploration -->
34
+ -
35
+
36
+ ## Technical Decisions
37
+ <!--
38
+ WHAT: Architecture and implementation choices you've made, with reasoning.
39
+ WHY: You'll forget why you chose a technology or approach. This table preserves that knowledge.
40
+ WHEN: Update whenever you make a significant technical choice.
41
+ EXAMPLE:
42
+ | Use JSON for storage | Simple, human-readable, built-in Python support |
43
+ | argparse with subcommands | Clean CLI: python todo.py add "task" |
44
+ -->
45
+ <!-- Decisions made with rationale -->
46
+ | Decision | Rationale |
47
+ |----------|-----------|
48
+ | | |
49
+
50
+ ## Issues Encountered
51
+ <!--
52
+ WHAT: Problems you ran into and how you solved them.
53
+ WHY: Similar to errors in task_plan.md, but focused on broader issues (not just code errors).
54
+ WHEN: Document when you encounter blockers or unexpected challenges.
55
+ EXAMPLE:
56
+ | Empty file causes JSONDecodeError | Added explicit empty file check before json.load() |
57
+ -->
58
+ <!-- Errors and how they were resolved -->
59
+ | Issue | Resolution |
60
+ |-------|------------|
61
+ | | |
62
+
63
+ ## Resources
64
+ <!--
65
+ WHAT: URLs, file paths, API references, documentation links you've found useful.
66
+ WHY: Easy reference for later. Don't lose important links in context.
67
+ WHEN: Add as you discover useful resources.
68
+ EXAMPLE:
69
+ - Python argparse docs: https://docs.python.org/3/library/argparse.html
70
+ - Project structure: src/main.py, src/utils.py
71
+ -->
72
+ <!-- URLs, file paths, API references -->
73
+ -
74
+
75
+ ## Visual/Browser Findings
76
+ <!--
77
+ WHAT: Information you learned from viewing images, PDFs, or browser results.
78
+ WHY: CRITICAL - Visual/multimodal content doesn't persist in context. Must be captured as text.
79
+ WHEN: IMMEDIATELY after viewing images or browser results. Don't wait!
80
+ EXAMPLE:
81
+ - Screenshot shows login form has email and password fields
82
+ - Browser shows API returns JSON with "status" and "data" keys
83
+ -->
84
+ <!-- CRITICAL: Update after every 2 view/browser operations -->
85
+ <!-- Multimodal content must be captured as text immediately -->
86
+ -
87
+
88
+ ---
89
+ <!--
90
+ REMINDER: The 2-Action Rule
91
+ After every 2 view/browser/search operations, you MUST update this file.
92
+ This prevents visual information from being lost when context resets.
93
+ -->
94
+ *Update this file after every 2 view/browser/search operations*
95
+ *This prevents visual information from being lost*
@@ -0,0 +1,114 @@
1
+ # Progress Log
2
+ <!--
3
+ WHAT: Your session log - a chronological record of what you did, when, and what happened.
4
+ WHY: Answers "What have I done?" in the 5-Question Reboot Test. Helps you resume after breaks.
5
+ WHEN: Update after completing each phase or encountering errors. More detailed than task_plan.md.
6
+ -->
7
+
8
+ ## Session: [DATE]
9
+ <!--
10
+ WHAT: The date of this work session.
11
+ WHY: Helps track when work happened, useful for resuming after time gaps.
12
+ EXAMPLE: 2026-01-15
13
+ -->
14
+
15
+ ### Phase 1: [Title]
16
+ <!--
17
+ WHAT: Detailed log of actions taken during this phase.
18
+ WHY: Provides context for what was done, making it easier to resume or debug.
19
+ WHEN: Update as you work through the phase, or at least when you complete it.
20
+ -->
21
+ - **Status:** in_progress
22
+ - **Started:** [timestamp]
23
+ <!--
24
+ STATUS: Same as task_plan.md (pending, in_progress, complete)
25
+ TIMESTAMP: When you started this phase (e.g., "2026-01-15 10:00")
26
+ -->
27
+ - Actions taken:
28
+ <!--
29
+ WHAT: List of specific actions you performed.
30
+ EXAMPLE:
31
+ - Created todo.py with basic structure
32
+ - Implemented add functionality
33
+ - Fixed FileNotFoundError
34
+ -->
35
+ -
36
+ - Files created/modified:
37
+ <!--
38
+ WHAT: Which files you created or changed.
39
+ WHY: Quick reference for what was touched. Helps with debugging and review.
40
+ EXAMPLE:
41
+ - todo.py (created)
42
+ - todos.json (created by app)
43
+ - task_plan.md (updated)
44
+ -->
45
+ -
46
+
47
+ ### Phase 2: [Title]
48
+ <!--
49
+ WHAT: Same structure as Phase 1, for the next phase.
50
+ WHY: Keep a separate log entry for each phase to track progress clearly.
51
+ -->
52
+ - **Status:** pending
53
+ - Actions taken:
54
+ -
55
+ - Files created/modified:
56
+ -
57
+
58
+ ## Test Results
59
+ <!--
60
+ WHAT: Table of tests you ran, what you expected, what actually happened.
61
+ WHY: Documents verification of functionality. Helps catch regressions.
62
+ WHEN: Update as you test features, especially during Phase 4 (Testing & Verification).
63
+ EXAMPLE:
64
+ | Add task | python todo.py add "Buy milk" | Task added | Task added successfully | ✓ |
65
+ | List tasks | python todo.py list | Shows all tasks | Shows all tasks | ✓ |
66
+ -->
67
+ | Test | Input | Expected | Actual | Status |
68
+ |------|-------|----------|--------|--------|
69
+ | | | | | |
70
+
71
+ ## Error Log
72
+ <!--
73
+ WHAT: Detailed log of every error encountered, with timestamps and resolution attempts.
74
+ WHY: More detailed than task_plan.md's error table. Helps you learn from mistakes.
75
+ WHEN: Add immediately when an error occurs, even if you fix it quickly.
76
+ EXAMPLE:
77
+ | 2026-01-15 10:35 | FileNotFoundError | 1 | Added file existence check |
78
+ | 2026-01-15 10:37 | JSONDecodeError | 2 | Added empty file handling |
79
+ -->
80
+ <!-- Keep ALL errors - they help avoid repetition -->
81
+ | Timestamp | Error | Attempt | Resolution |
82
+ |-----------|-------|---------|------------|
83
+ | | | 1 | |
84
+
85
+ ## 5-Question Reboot Check
86
+ <!--
87
+ WHAT: Five questions that verify your context is solid. If you can answer these, you're on track.
88
+ WHY: This is the "reboot test" - if you can answer all 5, you can resume work effectively.
89
+ WHEN: Update periodically, especially when resuming after a break or context reset.
90
+
91
+ THE 5 QUESTIONS:
92
+ 1. Where am I? → Current phase in task_plan.md
93
+ 2. Where am I going? → Remaining phases
94
+ 3. What's the goal? → Goal statement in task_plan.md
95
+ 4. What have I learned? → See findings.md
96
+ 5. What have I done? → See progress.md (this file)
97
+ -->
98
+ <!-- If you can answer these, context is solid -->
99
+ | Question | Answer |
100
+ |----------|--------|
101
+ | Where am I? | Phase X |
102
+ | Where am I going? | Remaining phases |
103
+ | What's the goal? | [goal statement] |
104
+ | What have I learned? | See findings.md |
105
+ | What have I done? | See above |
106
+
107
+ ---
108
+ <!--
109
+ REMINDER:
110
+ - Update after completing each phase or encountering errors
111
+ - Be detailed - this is your "what happened" log
112
+ - Include timestamps for errors to track when issues occurred
113
+ -->
114
+ *Update after completing each phase or encountering errors*
@@ -0,0 +1,132 @@
1
+ # Task Plan: [Brief Description]
2
+ <!--
3
+ WHAT: This is your roadmap for the entire task. Think of it as your "working memory on disk."
4
+ WHY: After 50+ tool calls, your original goals can get forgotten. This file keeps them fresh.
5
+ WHEN: Create this FIRST, before starting any work. Update after each phase completes.
6
+ -->
7
+
8
+ ## Goal
9
+ <!--
10
+ WHAT: One clear sentence describing what you're trying to achieve.
11
+ WHY: This is your north star. Re-reading this keeps you focused on the end state.
12
+ EXAMPLE: "Create a Python CLI todo app with add, list, and delete functionality."
13
+ -->
14
+ [One sentence describing the end state]
15
+
16
+ ## Current Phase
17
+ <!--
18
+ WHAT: Which phase you're currently working on (e.g., "Phase 1", "Phase 3").
19
+ WHY: Quick reference for where you are in the task. Update this as you progress.
20
+ -->
21
+ Phase 1
22
+
23
+ ## Phases
24
+ <!--
25
+ WHAT: Break your task into 3-7 logical phases. Each phase should be completable.
26
+ WHY: Breaking work into phases prevents overwhelm and makes progress visible.
27
+ WHEN: Update status after completing each phase: pending → in_progress → complete
28
+ -->
29
+
30
+ ### Phase 1: Requirements & Discovery
31
+ <!--
32
+ WHAT: Understand what needs to be done and gather initial information.
33
+ WHY: Starting without understanding leads to wasted effort. This phase prevents that.
34
+ -->
35
+ - [ ] Understand user intent
36
+ - [ ] Identify constraints and requirements
37
+ - [ ] Document findings in findings.md
38
+ - **Status:** in_progress
39
+ <!--
40
+ STATUS VALUES:
41
+ - pending: Not started yet
42
+ - in_progress: Currently working on this
43
+ - complete: Finished this phase
44
+ -->
45
+
46
+ ### Phase 2: Planning & Structure
47
+ <!--
48
+ WHAT: Decide how you'll approach the problem and what structure you'll use.
49
+ WHY: Good planning prevents rework. Document decisions so you remember why you chose them.
50
+ -->
51
+ - [ ] Define technical approach
52
+ - [ ] Create project structure if needed
53
+ - [ ] Document decisions with rationale
54
+ - **Status:** pending
55
+
56
+ ### Phase 3: Implementation
57
+ <!--
58
+ WHAT: Actually build/create/write the solution.
59
+ WHY: This is where the work happens. Break into smaller sub-tasks if needed.
60
+ -->
61
+ - [ ] Execute the plan step by step
62
+ - [ ] Write code to files before executing
63
+ - [ ] Test incrementally
64
+ - **Status:** pending
65
+
66
+ ### Phase 4: Testing & Verification
67
+ <!--
68
+ WHAT: Verify everything works and meets requirements.
69
+ WHY: Catching issues early saves time. Document test results in progress.md.
70
+ -->
71
+ - [ ] Verify all requirements met
72
+ - [ ] Document test results in progress.md
73
+ - [ ] Fix any issues found
74
+ - **Status:** pending
75
+
76
+ ### Phase 5: Delivery
77
+ <!--
78
+ WHAT: Final review and handoff to user.
79
+ WHY: Ensures nothing is forgotten and deliverables are complete.
80
+ -->
81
+ - [ ] Review all output files
82
+ - [ ] Ensure deliverables are complete
83
+ - [ ] Deliver to user
84
+ - **Status:** pending
85
+
86
+ ## Key Questions
87
+ <!--
88
+ WHAT: Important questions you need to answer during the task.
89
+ WHY: These guide your research and decision-making. Answer them as you go.
90
+ EXAMPLE:
91
+ 1. Should tasks persist between sessions? (Yes - need file storage)
92
+ 2. What format for storing tasks? (JSON file)
93
+ -->
94
+ 1. [Question to answer]
95
+ 2. [Question to answer]
96
+
97
+ ## Decisions Made
98
+ <!--
99
+ WHAT: Technical and design decisions you've made, with the reasoning behind them.
100
+ WHY: You'll forget why you made choices. This table helps you remember and justify decisions.
101
+ WHEN: Update whenever you make a significant choice (technology, approach, structure).
102
+ EXAMPLE:
103
+ | Use JSON for storage | Simple, human-readable, built-in Python support |
104
+ -->
105
+ | Decision | Rationale |
106
+ |----------|-----------|
107
+ | | |
108
+
109
+ ## Errors Encountered
110
+ <!--
111
+ WHAT: Every error you encounter, what attempt number it was, and how you resolved it.
112
+ WHY: Logging errors prevents repeating the same mistakes. This is critical for learning.
113
+ WHEN: Add immediately when an error occurs, even if you fix it quickly.
114
+ EXAMPLE:
115
+ | FileNotFoundError | 1 | Check if file exists, create empty list if not |
116
+ | JSONDecodeError | 2 | Handle empty file case explicitly |
117
+ -->
118
+ | Error | Attempt | Resolution |
119
+ |-------|---------|------------|
120
+ | | 1 | |
121
+
122
+ ## Notes
123
+ <!--
124
+ REMINDERS:
125
+ - Update phase status as you progress: pending → in_progress → complete
126
+ - Re-read this plan before major decisions (attention manipulation)
127
+ - Log ALL errors - they help avoid repetition
128
+ - Never repeat a failed action - mutate your approach instead
129
+ -->
130
+ - Update phase status as you progress: pending → in_progress → complete
131
+ - Re-read this plan before major decisions (attention manipulation)
132
+ - Log ALL errors - they help avoid repetition