Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acfd2f0c74 | ||
|
|
931bb545ab | ||
|
|
15e33d261a | ||
|
|
6e8f128a79 | ||
|
|
7a0d05145a | ||
|
|
d1ee93c567 | ||
|
|
f45b39a967 | ||
|
|
af533413ca | ||
|
|
461fc525de | ||
|
|
8104801106 | ||
|
|
a8ce293833 | ||
|
|
d604849947 | ||
|
|
0f2a9cfba4 | ||
|
|
d8d5002736 | ||
|
|
428728f5f2 | ||
|
|
d4b699ccf1 | ||
|
|
dde2a69913 | ||
|
|
d69eda6b31 | ||
|
|
6a9effe7d7 | ||
|
|
bc642b9bf6 | ||
|
|
f3c07ea4c7 | ||
|
|
3a8547ff24 | ||
|
|
4292f000a1 | ||
|
|
245726ee5b | ||
|
|
70fc70b682 | ||
|
|
ec84b78408 | ||
|
|
e18d267d24 | ||
|
|
cb5f10ba5f | ||
|
|
9fc3f3ff28 | ||
|
|
0c1ddd21c3 | ||
|
|
a233b1b430 | ||
|
|
61e6165e2f | ||
|
|
4e5084cde4 | ||
|
|
0361bf17c4 | ||
|
|
abc11dd858 | ||
|
|
c7e3b71bb8 | ||
|
|
8adf37c6f8 | ||
|
|
eb27664be1 | ||
|
|
ab208d9d92 | ||
|
|
7082c7f41f | ||
|
|
8a49fdb03a | ||
|
|
7f73508511 | ||
|
|
0225360606 | ||
|
|
0b033eb025 | ||
|
|
9ec4d413b6 | ||
|
|
b96b42a9e5 | ||
|
|
16fd096f4f |
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "ERROR: $PlanFile not found"
|
||||
Write-Host "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "=== Task Completion Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count phases by status
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
Write-Host "Total phases: $TOTAL"
|
||||
Write-Host "Complete: $COMPLETE"
|
||||
Write-Host "In progress: $IN_PROGRESS"
|
||||
Write-Host "Pending: $PENDING"
|
||||
Write-Host ""
|
||||
|
||||
# Check completion
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "TASK NOT COMPLETE"
|
||||
Write-Host ""
|
||||
Write-Host "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "ERROR: $PLAN_FILE not found"
|
||||
echo "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== Task Completion Check ==="
|
||||
echo ""
|
||||
|
||||
# Count phases by status (using -F for fixed string matching)
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
echo "Total phases: $TOTAL"
|
||||
echo "Complete: $COMPLETE"
|
||||
echo "In progress: $IN_PROGRESS"
|
||||
echo "Pending: $PENDING"
|
||||
echo ""
|
||||
|
||||
# Check completion
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "TASK NOT COMPLETE"
|
||||
echo ""
|
||||
echo "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
"""
|
||||
Session Catchup Script for planning-with-files
|
||||
|
||||
Session-agnostic scanning: finds the most recent planning file update across
|
||||
ALL sessions, then collects all conversation from that point forward through
|
||||
all subsequent sessions until now.
|
||||
Analyzes the previous session to find unsynced context after the last
|
||||
planning file update. Designed to run on SessionStart.
|
||||
|
||||
Usage: python3 session-catchup.py [project-path]
|
||||
"""
|
||||
@@ -14,6 +13,7 @@ import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
from datetime import datetime
|
||||
|
||||
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
|
||||
|
||||
@@ -34,147 +34,106 @@ def get_sessions_sorted(project_dir: Path) -> List[Path]:
|
||||
return sorted(main_sessions, key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
|
||||
|
||||
def get_session_first_timestamp(session_file: Path) -> Optional[str]:
|
||||
"""Get the timestamp of the first message in a session."""
|
||||
try:
|
||||
with open(session_file, 'r') as f:
|
||||
for line in f:
|
||||
try:
|
||||
data = json.loads(line)
|
||||
ts = data.get('timestamp')
|
||||
if ts:
|
||||
return ts
|
||||
except:
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
def parse_session_messages(session_file: Path) -> List[Dict]:
|
||||
"""Parse all messages from a session file, preserving order."""
|
||||
messages = []
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
try:
|
||||
data = json.loads(line)
|
||||
data['_line_num'] = line_num
|
||||
messages.append(data)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return messages
|
||||
|
||||
|
||||
def scan_for_planning_update(session_file: Path) -> Tuple[int, Optional[str]]:
|
||||
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
|
||||
"""
|
||||
Quickly scan a session file for planning file updates.
|
||||
Returns (line_number, filename) of last update, or (-1, None) if none found.
|
||||
Find the last time a planning file was written/edited.
|
||||
Returns (line_number, filename) or (-1, None) if not found.
|
||||
"""
|
||||
last_update_line = -1
|
||||
last_update_file = None
|
||||
|
||||
try:
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
if '"Write"' not in line and '"Edit"' not in line:
|
||||
continue
|
||||
for msg in messages:
|
||||
msg_type = msg.get('type')
|
||||
|
||||
try:
|
||||
data = json.loads(line)
|
||||
if data.get('type') != 'assistant':
|
||||
continue
|
||||
|
||||
content = data.get('message', {}).get('content', [])
|
||||
if not isinstance(content, list):
|
||||
continue
|
||||
|
||||
for item in content:
|
||||
if item.get('type') != 'tool_use':
|
||||
continue
|
||||
if msg_type == 'assistant':
|
||||
content = msg.get('message', {}).get('content', [])
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
if tool_name not in ('Write', 'Edit'):
|
||||
continue
|
||||
tool_input = item.get('input', {})
|
||||
|
||||
file_path = item.get('input', {}).get('file_path', '')
|
||||
for pf in PLANNING_FILES:
|
||||
if file_path.endswith(pf):
|
||||
last_update_line = line_num
|
||||
last_update_file = pf
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
if tool_name in ('Write', 'Edit'):
|
||||
file_path = tool_input.get('file_path', '')
|
||||
for pf in PLANNING_FILES:
|
||||
if file_path.endswith(pf):
|
||||
last_update_line = msg['_line_num']
|
||||
last_update_file = pf
|
||||
|
||||
return last_update_line, last_update_file
|
||||
|
||||
|
||||
def extract_messages_from_session(session_file: Path, after_line: int = -1) -> List[Dict]:
|
||||
"""
|
||||
Extract conversation messages from a session file.
|
||||
If after_line >= 0, only extract messages after that line.
|
||||
If after_line < 0, extract all messages.
|
||||
"""
|
||||
def extract_messages_after(messages: List[Dict], after_line: int) -> List[Dict]:
|
||||
"""Extract conversation messages after a certain line number."""
|
||||
result = []
|
||||
for msg in messages:
|
||||
if msg['_line_num'] <= after_line:
|
||||
continue
|
||||
|
||||
try:
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
if after_line >= 0 and line_num <= after_line:
|
||||
msg_type = msg.get('type')
|
||||
is_meta = msg.get('isMeta', False)
|
||||
|
||||
if msg_type == 'user' and not is_meta:
|
||||
content = msg.get('message', {}).get('content', '')
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get('type') == 'text':
|
||||
content = item.get('text', '')
|
||||
break
|
||||
else:
|
||||
content = ''
|
||||
|
||||
if content and isinstance(content, str):
|
||||
if content.startswith(('<local-command', '<command-', '<task-notification')):
|
||||
continue
|
||||
if len(content) > 20:
|
||||
result.append({'role': 'user', 'content': content, 'line': msg['_line_num']})
|
||||
|
||||
try:
|
||||
msg = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
elif msg_type == 'assistant':
|
||||
msg_content = msg.get('message', {}).get('content', '')
|
||||
text_content = ''
|
||||
tool_uses = []
|
||||
|
||||
msg_type = msg.get('type')
|
||||
is_meta = msg.get('isMeta', False)
|
||||
|
||||
if msg_type == 'user' and not is_meta:
|
||||
content = msg.get('message', {}).get('content', '')
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get('type') == 'text':
|
||||
content = item.get('text', '')
|
||||
break
|
||||
if isinstance(msg_content, str):
|
||||
text_content = msg_content
|
||||
elif isinstance(msg_content, list):
|
||||
for item in msg_content:
|
||||
if item.get('type') == 'text':
|
||||
text_content = item.get('text', '')
|
||||
elif item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
if tool_name == 'Edit':
|
||||
tool_uses.append(f"Edit: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Write':
|
||||
tool_uses.append(f"Write: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Bash':
|
||||
cmd = tool_input.get('command', '')[:80]
|
||||
tool_uses.append(f"Bash: {cmd}")
|
||||
else:
|
||||
content = ''
|
||||
tool_uses.append(f"{tool_name}")
|
||||
|
||||
if content and isinstance(content, str):
|
||||
# Skip system/command messages
|
||||
if content.startswith(('<local-command', '<command-', '<task-notification')):
|
||||
continue
|
||||
if len(content) > 20:
|
||||
result.append({
|
||||
'role': 'user',
|
||||
'content': content,
|
||||
'line': line_num,
|
||||
'session': session_file.stem[:8]
|
||||
})
|
||||
|
||||
elif msg_type == 'assistant':
|
||||
msg_content = msg.get('message', {}).get('content', '')
|
||||
text_content = ''
|
||||
tool_uses = []
|
||||
|
||||
if isinstance(msg_content, str):
|
||||
text_content = msg_content
|
||||
elif isinstance(msg_content, list):
|
||||
for item in msg_content:
|
||||
if item.get('type') == 'text':
|
||||
text_content = item.get('text', '')
|
||||
elif item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
if tool_name == 'Edit':
|
||||
tool_uses.append(f"Edit: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Write':
|
||||
tool_uses.append(f"Write: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Bash':
|
||||
cmd = tool_input.get('command', '')[:80]
|
||||
tool_uses.append(f"Bash: {cmd}")
|
||||
elif tool_name == 'AskUserQuestion':
|
||||
tool_uses.append("AskUserQuestion")
|
||||
else:
|
||||
tool_uses.append(f"{tool_name}")
|
||||
|
||||
if text_content or tool_uses:
|
||||
result.append({
|
||||
'role': 'assistant',
|
||||
'content': text_content[:600] if text_content else '',
|
||||
'tools': tool_uses,
|
||||
'line': line_num,
|
||||
'session': session_file.stem[:8]
|
||||
})
|
||||
except Exception:
|
||||
pass
|
||||
if text_content or tool_uses:
|
||||
result.append({
|
||||
'role': 'assistant',
|
||||
'content': text_content[:600] if text_content else '',
|
||||
'tools': tool_uses,
|
||||
'line': msg['_line_num']
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
@@ -183,82 +142,54 @@ def main():
|
||||
project_path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
||||
project_dir = get_project_dir(project_path)
|
||||
|
||||
# Check if planning files exist (indicates active task)
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise.
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# No previous sessions, nothing to catch up on
|
||||
return
|
||||
|
||||
sessions = get_sessions_sorted(project_dir)
|
||||
if len(sessions) < 2:
|
||||
if len(sessions) < 1:
|
||||
return
|
||||
|
||||
# Skip the current session (most recently modified = index 0)
|
||||
previous_sessions = sessions[1:]
|
||||
|
||||
# Find the most recent planning file update across ALL previous sessions
|
||||
# Sessions are sorted newest first, so we scan in order
|
||||
update_session = None
|
||||
update_line = -1
|
||||
update_file = None
|
||||
update_session_idx = -1
|
||||
|
||||
for idx, session in enumerate(previous_sessions):
|
||||
line, filename = scan_for_planning_update(session)
|
||||
if line >= 0:
|
||||
update_session = session
|
||||
update_line = line
|
||||
update_file = filename
|
||||
update_session_idx = idx
|
||||
# Find a substantial previous session
|
||||
target_session = None
|
||||
for session in sessions:
|
||||
if session.stat().st_size > 5000:
|
||||
target_session = session
|
||||
break
|
||||
|
||||
if not update_session:
|
||||
# No planning file updates found in any previous session
|
||||
if not target_session:
|
||||
return
|
||||
|
||||
# Collect ALL messages from the update point forward, across all sessions
|
||||
all_messages = []
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# 1. Get messages from the session with the update (after the update line)
|
||||
messages_from_update_session = extract_messages_from_session(update_session, after_line=update_line)
|
||||
all_messages.extend(messages_from_update_session)
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
return
|
||||
|
||||
# 2. Get ALL messages from sessions between update_session and current
|
||||
# These are sessions[1:update_session_idx] (newer than update_session)
|
||||
intermediate_sessions = previous_sessions[:update_session_idx]
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
# Process from oldest to newest for correct chronological order
|
||||
for session in reversed(intermediate_sessions):
|
||||
messages = extract_messages_from_session(session, after_line=-1) # Get all messages
|
||||
all_messages.extend(messages)
|
||||
|
||||
if not all_messages:
|
||||
if not messages_after:
|
||||
return
|
||||
|
||||
# Output catchup report
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Last planning update: {update_file} in session {update_session.stem[:8]}...")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
sessions_covered = update_session_idx + 1
|
||||
if sessions_covered > 1:
|
||||
print(f"Scanning {sessions_covered} sessions for unsynced context")
|
||||
|
||||
print(f"Unsynced messages: {len(all_messages)}")
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
|
||||
# Show up to 100 messages
|
||||
MAX_MESSAGES = 100
|
||||
if len(all_messages) > MAX_MESSAGES:
|
||||
print(f"(Showing last {MAX_MESSAGES} of {len(all_messages)} messages)\n")
|
||||
messages_to_show = all_messages[-MAX_MESSAGES:]
|
||||
else:
|
||||
messages_to_show = all_messages
|
||||
|
||||
current_session = None
|
||||
for msg in messages_to_show:
|
||||
# Show session marker when it changes
|
||||
if msg.get('session') != current_session:
|
||||
current_session = msg.get('session')
|
||||
print(f"\n[Session: {current_session}...]")
|
||||
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
if msg['role'] == 'user':
|
||||
print(f"USER: {msg['content'][:300]}")
|
||||
else:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
license: MIT
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "planning-with-files",
|
||||
"version": "2.11.0",
|
||||
"version": "2.17.0",
|
||||
"description": "Manus-style persistent markdown files for planning, progress tracking, and knowledge storage. Works with Claude Code, Kiro, Clawd CLI, Gemini CLI, Cursor, Continue, and 11+ AI coding assistants.",
|
||||
"author": {
|
||||
"name": "OthmanAdi",
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.10.0"
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls. Now with automatic session recovery after /clear.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
user-invocable: true
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Bash
|
||||
- Glob
|
||||
- Grep
|
||||
- WebFetch
|
||||
- WebSearch
|
||||
allowed-tools: "Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch"
|
||||
hooks:
|
||||
PreToolUse:
|
||||
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
|
||||
@@ -27,7 +18,7 @@ hooks:
|
||||
- hooks:
|
||||
- type: command
|
||||
command: |
|
||||
SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/planning-with-files}/scripts"
|
||||
SCRIPT_DIR="${CODEBUDDY_PLUGIN_ROOT:-$HOME/.codebuddy/skills/planning-with-files}/scripts"
|
||||
|
||||
IS_WINDOWS=0
|
||||
if [ "${OS-}" = "Windows_NT" ]; then
|
||||
@@ -51,6 +42,8 @@ hooks:
|
||||
else
|
||||
sh "$SCRIPT_DIR/check-complete.sh"
|
||||
fi
|
||||
metadata:
|
||||
version: "2.16.1"
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
@@ -63,7 +56,7 @@ Work like Manus: Use persistent markdown files as your "working memory on disk."
|
||||
|
||||
```bash
|
||||
# Linux/macOS (auto-detects python3 or python)
|
||||
$(command -v python3 || command -v python) ${CLAUDE_PLUGIN_ROOT}/scripts/session-catchup.py "$(pwd)"
|
||||
$(command -v python3 || command -v python) ${CODEBUDDY_PLUGIN_ROOT}/scripts/session-catchup.py "$(pwd)"
|
||||
```
|
||||
|
||||
```powershell
|
||||
@@ -79,12 +72,12 @@ If catchup report shows unsynced context:
|
||||
|
||||
## Important: Where Files Go
|
||||
|
||||
- **Templates** are in `${CLAUDE_PLUGIN_ROOT}/templates/`
|
||||
- **Templates** are in `${CODEBUDDY_PLUGIN_ROOT}/templates/`
|
||||
- **Your planning files** go in **your project directory**
|
||||
|
||||
| Location | What Goes There |
|
||||
|----------|-----------------|
|
||||
| Skill directory (`${CLAUDE_PLUGIN_ROOT}/`) | Templates, scripts, reference docs |
|
||||
| Skill directory (`${CODEBUDDY_PLUGIN_ROOT}/`) | Templates, scripts, reference docs |
|
||||
| Your project directory | `task_plan.md`, `findings.md`, `progress.md` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "ERROR: $PlanFile not found"
|
||||
Write-Host "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "=== Task Completion Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count phases by status
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
Write-Host "Total phases: $TOTAL"
|
||||
Write-Host "Complete: $COMPLETE"
|
||||
Write-Host "In progress: $IN_PROGRESS"
|
||||
Write-Host "Pending: $PENDING"
|
||||
Write-Host ""
|
||||
|
||||
# Check completion
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "TASK NOT COMPLETE"
|
||||
Write-Host ""
|
||||
Write-Host "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "ERROR: $PLAN_FILE not found"
|
||||
echo "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== Task Completion Check ==="
|
||||
echo ""
|
||||
|
||||
# Count phases by status (using -F for fixed string matching)
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
echo "Total phases: $TOTAL"
|
||||
echo "Complete: $COMPLETE"
|
||||
echo "In progress: $IN_PROGRESS"
|
||||
echo "Pending: $PENDING"
|
||||
echo ""
|
||||
|
||||
# Check completion
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "TASK NOT COMPLETE"
|
||||
echo ""
|
||||
echo "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -19,12 +19,12 @@ PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
|
||||
|
||||
|
||||
def get_project_dir(project_path: str) -> Path:
|
||||
"""Convert project path to Claude's storage path format."""
|
||||
"""Convert project path to CodeBuddy's storage path format."""
|
||||
sanitized = project_path.replace('/', '-')
|
||||
if not sanitized.startswith('-'):
|
||||
sanitized = '-' + sanitized
|
||||
sanitized = sanitized.replace('_', '-')
|
||||
return Path.home() / '.claude' / 'projects' / sanitized
|
||||
return Path.home() / '.codebuddy' / 'projects' / sanitized
|
||||
|
||||
|
||||
def get_sessions_sorted(project_dir: Path) -> List[Path]:
|
||||
@@ -146,6 +146,9 @@ def main():
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise.
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# No previous sessions, nothing to catch up on
|
||||
@@ -168,11 +171,12 @@ def main():
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# Only output if there's unsynced content
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
messages_after = extract_messages_after(messages, len(messages) - 30)
|
||||
else:
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
return
|
||||
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
if not messages_after:
|
||||
return
|
||||
@@ -181,11 +185,8 @@ def main():
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
if last_update_line >= 0:
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
else:
|
||||
print("No planning file updates found in previous session")
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
@@ -193,7 +194,7 @@ def main():
|
||||
print(f"USER: {msg['content'][:300]}")
|
||||
else:
|
||||
if msg.get('content'):
|
||||
print(f"CLAUDE: {msg['content'][:300]}")
|
||||
print(f"CODEBUDDY: {msg['content'][:300]}")
|
||||
if msg.get('tools'):
|
||||
print(f" Tools: {', '.join(msg['tools'][:4])}")
|
||||
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.10.0"
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls. Now with automatic session recovery after /clear.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
user-invocable: true
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Bash
|
||||
- Glob
|
||||
- Grep
|
||||
- WebFetch
|
||||
- WebSearch
|
||||
allowed-tools: "Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch"
|
||||
hooks:
|
||||
PreToolUse:
|
||||
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
|
||||
@@ -51,6 +42,8 @@ hooks:
|
||||
else
|
||||
sh "$SCRIPT_DIR/check-complete.sh"
|
||||
fi
|
||||
metadata:
|
||||
version: "2.16.1"
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "ERROR: $PlanFile not found"
|
||||
Write-Host "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "=== Task Completion Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count phases by status
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
Write-Host "Total phases: $TOTAL"
|
||||
Write-Host "Complete: $COMPLETE"
|
||||
Write-Host "In progress: $IN_PROGRESS"
|
||||
Write-Host "Pending: $PENDING"
|
||||
Write-Host ""
|
||||
|
||||
# Check completion
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "TASK NOT COMPLETE"
|
||||
Write-Host ""
|
||||
Write-Host "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "ERROR: $PLAN_FILE not found"
|
||||
echo "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== Task Completion Check ==="
|
||||
echo ""
|
||||
|
||||
# Count phases by status (using -F for fixed string matching)
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
echo "Total phases: $TOTAL"
|
||||
echo "Complete: $COMPLETE"
|
||||
echo "In progress: $IN_PROGRESS"
|
||||
echo "Pending: $PENDING"
|
||||
echo ""
|
||||
|
||||
# Check completion
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "TASK NOT COMPLETE"
|
||||
echo ""
|
||||
echo "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -146,6 +146,9 @@ def main():
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise.
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# No previous sessions, nothing to catch up on
|
||||
@@ -168,11 +171,12 @@ def main():
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# Only output if there's unsynced content
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
messages_after = extract_messages_after(messages, len(messages) - 30)
|
||||
else:
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
return
|
||||
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
if not messages_after:
|
||||
return
|
||||
@@ -181,11 +185,8 @@ def main():
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
if last_update_line >= 0:
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
else:
|
||||
print("No planning file updates found in previous session")
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.10.0"
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls. Now with automatic session recovery after /clear.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
metadata:
|
||||
version: "2.16.1"
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
@@ -188,7 +188,7 @@ Success!
|
||||
|
||||
## The Read-Before-Decide Pattern
|
||||
|
||||
Always read your plan before major decisions:
|
||||
**Always read your plan before major decisions:**
|
||||
|
||||
```
|
||||
[Many tool calls have happened...]
|
||||
|
||||
@@ -170,7 +170,7 @@ Manus operates in a continuous 7-step loop:
|
||||
| File | Purpose | When Created | When Updated |
|
||||
|------|---------|--------------|--------------|
|
||||
| `task_plan.md` | Phase tracking, progress | Task start | After completing phases |
|
||||
| `findings.md` | Discoveries, decisions | After any discovery | After viewing images/PDFs |
|
||||
| `findings.md` | Discoveries, decisions | After ANY discovery | After viewing images/PDFs |
|
||||
| `progress.md` | Session log, what's done | At breakpoints | Throughout session |
|
||||
| Code files | Implementation | Before execution | After errors |
|
||||
|
||||
@@ -178,11 +178,11 @@ Manus operates in a continuous 7-step loop:
|
||||
|
||||
## Critical Constraints
|
||||
|
||||
- Single-action execution: one tool call per turn
|
||||
- Plan is required: always know goal, current phase, remaining phases
|
||||
- Files are memory: context is volatile; filesystem is persistent
|
||||
- Never repeat failures: if action failed, next action must be different
|
||||
- Communication is a tool: message types include info, ask, result
|
||||
- **Single-Action Execution:** ONE tool call per turn. No parallel execution.
|
||||
- **Plan is Required:** Agent must ALWAYS know: goal, current phase, remaining phases
|
||||
- **Files are Memory:** Context = volatile. Filesystem = persistent.
|
||||
- **Never Repeat Failures:** If action failed, next action MUST be different
|
||||
- **Communication is a Tool:** Message types: `info` (progress), `ask` (blocking), `result` (terminal)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "ERROR: $PlanFile not found"
|
||||
Write-Host "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "=== Task Completion Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count phases by status
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
Write-Host "Total phases: $TOTAL"
|
||||
Write-Host "Complete: $COMPLETE"
|
||||
Write-Host "In progress: $IN_PROGRESS"
|
||||
Write-Host "Pending: $PENDING"
|
||||
Write-Host ""
|
||||
|
||||
# Check completion
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "TASK NOT COMPLETE"
|
||||
Write-Host ""
|
||||
Write-Host "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "ERROR: $PLAN_FILE not found"
|
||||
echo "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== Task Completion Check ==="
|
||||
echo ""
|
||||
|
||||
# Count phases by status (using -F for fixed string matching)
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
echo "Total phases: $TOTAL"
|
||||
echo "Complete: $COMPLETE"
|
||||
echo "In progress: $IN_PROGRESS"
|
||||
echo "Pending: $PENDING"
|
||||
echo ""
|
||||
|
||||
# Check completion
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "TASK NOT COMPLETE"
|
||||
echo ""
|
||||
echo "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -142,17 +142,23 @@ def main():
|
||||
project_path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
||||
project_dir = get_project_dir(project_path)
|
||||
|
||||
# Check if planning files exist (indicates active task)
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise.
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# No previous sessions, nothing to catch up on
|
||||
return
|
||||
|
||||
sessions = get_sessions_sorted(project_dir)
|
||||
if len(sessions) < 1:
|
||||
return
|
||||
|
||||
# Find a substantial previous session
|
||||
target_session = None
|
||||
for session in sessions:
|
||||
if session.stat().st_size > 5000:
|
||||
@@ -165,25 +171,25 @@ def main():
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
messages_after = extract_messages_after(messages, len(messages) - 30)
|
||||
else:
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
return
|
||||
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
if not messages_after:
|
||||
return
|
||||
|
||||
# Output catchup report
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
if last_update_line >= 0:
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
else:
|
||||
print("No planning file updates found in previous session")
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
for msg in messages_after[-15:]:
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
if msg['role'] == 'user':
|
||||
print(f"USER: {msg['content'][:300]}")
|
||||
else:
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"preToolUse": [
|
||||
{
|
||||
"command": ".cursor/hooks/pre-tool-use.sh",
|
||||
"matcher": "Write|Edit|Shell|Read",
|
||||
"timeout": 5
|
||||
}
|
||||
],
|
||||
"postToolUse": [
|
||||
{
|
||||
"command": ".cursor/hooks/post-tool-use.sh",
|
||||
"matcher": "Write|Edit",
|
||||
"timeout": 5
|
||||
}
|
||||
],
|
||||
"stop": [
|
||||
{
|
||||
"command": ".cursor/hooks/stop.sh",
|
||||
"timeout": 10,
|
||||
"loop_limit": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"preToolUse": [
|
||||
{
|
||||
"command": "powershell -ExecutionPolicy Bypass -File .cursor/hooks/pre-tool-use.ps1",
|
||||
"matcher": "Write|Edit|Shell|Read",
|
||||
"timeout": 5
|
||||
}
|
||||
],
|
||||
"postToolUse": [
|
||||
{
|
||||
"command": "powershell -ExecutionPolicy Bypass -File .cursor/hooks/post-tool-use.ps1",
|
||||
"matcher": "Write|Edit",
|
||||
"timeout": 5
|
||||
}
|
||||
],
|
||||
"stop": [
|
||||
{
|
||||
"command": "powershell -ExecutionPolicy Bypass -File .cursor/hooks/stop.ps1",
|
||||
"timeout": 10,
|
||||
"loop_limit": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# planning-with-files: Post-tool-use hook for Cursor (PowerShell)
|
||||
# Reminds the agent to update task_plan.md after file modifications.
|
||||
|
||||
Write-Output "[planning-with-files] File updated. If this completes a phase, update task_plan.md status."
|
||||
exit 0
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
# planning-with-files: Post-tool-use hook for Cursor
|
||||
# Reminds the agent to update task_plan.md after file modifications.
|
||||
|
||||
echo "[planning-with-files] File updated. If this completes a phase, update task_plan.md status."
|
||||
exit 0
|
||||
@@ -0,0 +1,12 @@
|
||||
# planning-with-files: Pre-tool-use hook for Cursor (PowerShell)
|
||||
# Reads the first 30 lines of task_plan.md to keep goals in context.
|
||||
# Returns {"decision": "allow"} — this hook never blocks tools.
|
||||
|
||||
$PlanFile = "task_plan.md"
|
||||
|
||||
if (Test-Path $PlanFile) {
|
||||
Get-Content $PlanFile -TotalCount 30 | Write-Host
|
||||
}
|
||||
|
||||
Write-Output '{"decision": "allow"}'
|
||||
exit 0
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# planning-with-files: Pre-tool-use hook for Cursor
|
||||
# Reads the first 30 lines of task_plan.md to keep goals in context.
|
||||
# Returns {"decision": "allow"} — this hook never blocks tools.
|
||||
|
||||
PLAN_FILE="task_plan.md"
|
||||
|
||||
if [ -f "$PLAN_FILE" ]; then
|
||||
# Log plan context to stderr (visible in Cursor's hook logs)
|
||||
head -30 "$PLAN_FILE" >&2
|
||||
fi
|
||||
|
||||
echo '{"decision": "allow"}'
|
||||
exit 0
|
||||
@@ -0,0 +1,33 @@
|
||||
# planning-with-files: Stop hook for Cursor (PowerShell)
|
||||
# Checks if all phases in task_plan.md are complete.
|
||||
# Returns followup_message to auto-continue if phases are incomplete.
|
||||
# Always exits 0 — uses JSON stdout for control.
|
||||
|
||||
$PlanFile = "task_plan.md"
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
exit 0
|
||||
}
|
||||
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
# Fallback: check for [complete] inline format
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "{`"followup_message`": `"[planning-with-files] Task incomplete ($COMPLETE/$TOTAL phases done). Read task_plan.md and continue working on the remaining phases.`"}"
|
||||
exit 0
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# planning-with-files: Stop hook for Cursor
|
||||
# Checks if all phases in task_plan.md are complete.
|
||||
# Returns followup_message to auto-continue if phases are incomplete.
|
||||
# Always exits 0 — uses JSON stdout for control.
|
||||
|
||||
PLAN_FILE="task_plan.md"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
# No plan file = no planning session, allow stop
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
# All phases complete, allow stop
|
||||
exit 0
|
||||
else
|
||||
# Phases incomplete — auto-continue via followup_message
|
||||
echo "{\"followup_message\": \"[planning-with-files] Task incomplete ($COMPLETE/$TOTAL phases done). Read task_plan.md and continue working on the remaining phases.\"}"
|
||||
exit 0
|
||||
fi
|
||||
@@ -1,17 +1,8 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.10.0"
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls. Now with automatic session recovery after /clear.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
user-invocable: true
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Bash
|
||||
- Glob
|
||||
- Grep
|
||||
- WebFetch
|
||||
- WebSearch
|
||||
allowed-tools: "Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch"
|
||||
hooks:
|
||||
PreToolUse:
|
||||
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
|
||||
@@ -27,7 +18,7 @@ hooks:
|
||||
- hooks:
|
||||
- type: command
|
||||
command: |
|
||||
SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/planning-with-files}/scripts"
|
||||
SCRIPT_DIR="${CURSOR_SKILL_ROOT:-.cursor/skills/planning-with-files}/scripts"
|
||||
|
||||
IS_WINDOWS=0
|
||||
if [ "${OS-}" = "Windows_NT" ]; then
|
||||
@@ -51,6 +42,8 @@ hooks:
|
||||
else
|
||||
sh "$SCRIPT_DIR/check-complete.sh"
|
||||
fi
|
||||
metadata:
|
||||
version: "2.16.1"
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
@@ -63,7 +56,7 @@ Work like Manus: Use persistent markdown files as your "working memory on disk."
|
||||
|
||||
```bash
|
||||
# Linux/macOS (auto-detects python3 or python)
|
||||
$(command -v python3 || command -v python) ${CLAUDE_PLUGIN_ROOT}/scripts/session-catchup.py "$(pwd)"
|
||||
$(command -v python3 || command -v python) .cursor/skills/planning-with-files/scripts/session-catchup.py "$(pwd)"
|
||||
```
|
||||
|
||||
```powershell
|
||||
@@ -79,12 +72,12 @@ If catchup report shows unsynced context:
|
||||
|
||||
## Important: Where Files Go
|
||||
|
||||
- **Templates** are in `${CLAUDE_PLUGIN_ROOT}/templates/`
|
||||
- **Templates** are in `.cursor/skills/planning-with-files/templates/`
|
||||
- **Your planning files** go in **your project directory**
|
||||
|
||||
| Location | What Goes There |
|
||||
|----------|-----------------|
|
||||
| Skill directory (`${CLAUDE_PLUGIN_ROOT}/`) | Templates, scripts, reference docs |
|
||||
| Skill directory (`.cursor/skills/planning-with-files/`) | Templates, scripts, reference docs |
|
||||
| Your project directory | `task_plan.md`, `findings.md`, `progress.md` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "ERROR: $PlanFile not found"
|
||||
Write-Host "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "=== Task Completion Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count phases by status
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
Write-Host "Total phases: $TOTAL"
|
||||
Write-Host "Complete: $COMPLETE"
|
||||
Write-Host "In progress: $IN_PROGRESS"
|
||||
Write-Host "Pending: $PENDING"
|
||||
Write-Host ""
|
||||
|
||||
# Check completion
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "TASK NOT COMPLETE"
|
||||
Write-Host ""
|
||||
Write-Host "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "ERROR: $PLAN_FILE not found"
|
||||
echo "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== Task Completion Check ==="
|
||||
echo ""
|
||||
|
||||
# Count phases by status (using -F for fixed string matching)
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
echo "Total phases: $TOTAL"
|
||||
echo "Complete: $COMPLETE"
|
||||
echo "In progress: $IN_PROGRESS"
|
||||
echo "Pending: $PENDING"
|
||||
echo ""
|
||||
|
||||
# Check completion
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "TASK NOT COMPLETE"
|
||||
echo ""
|
||||
echo "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Session Catchup Script for planning-with-files
|
||||
|
||||
Analyzes the previous session to find unsynced context after the last
|
||||
planning file update. Designed to run on SessionStart.
|
||||
|
||||
Usage: python3 session-catchup.py [project-path]
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
from datetime import datetime
|
||||
|
||||
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
|
||||
|
||||
|
||||
def get_project_dir(project_path: str) -> Path:
|
||||
"""Convert project path to Claude's storage path format."""
|
||||
sanitized = project_path.replace('/', '-')
|
||||
if not sanitized.startswith('-'):
|
||||
sanitized = '-' + sanitized
|
||||
sanitized = sanitized.replace('_', '-')
|
||||
return Path.home() / '.claude' / 'projects' / sanitized
|
||||
|
||||
|
||||
def get_sessions_sorted(project_dir: Path) -> List[Path]:
|
||||
"""Get all session files sorted by modification time (newest first)."""
|
||||
sessions = list(project_dir.glob('*.jsonl'))
|
||||
main_sessions = [s for s in sessions if not s.name.startswith('agent-')]
|
||||
return sorted(main_sessions, key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
|
||||
|
||||
def parse_session_messages(session_file: Path) -> List[Dict]:
|
||||
"""Parse all messages from a session file, preserving order."""
|
||||
messages = []
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
try:
|
||||
data = json.loads(line)
|
||||
data['_line_num'] = line_num
|
||||
messages.append(data)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return messages
|
||||
|
||||
|
||||
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
|
||||
"""
|
||||
Find the last time a planning file was written/edited.
|
||||
Returns (line_number, filename) or (-1, None) if not found.
|
||||
"""
|
||||
last_update_line = -1
|
||||
last_update_file = None
|
||||
|
||||
for msg in messages:
|
||||
msg_type = msg.get('type')
|
||||
|
||||
if msg_type == 'assistant':
|
||||
content = msg.get('message', {}).get('content', [])
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
|
||||
if tool_name in ('Write', 'Edit'):
|
||||
file_path = tool_input.get('file_path', '')
|
||||
for pf in PLANNING_FILES:
|
||||
if file_path.endswith(pf):
|
||||
last_update_line = msg['_line_num']
|
||||
last_update_file = pf
|
||||
|
||||
return last_update_line, last_update_file
|
||||
|
||||
|
||||
def extract_messages_after(messages: List[Dict], after_line: int) -> List[Dict]:
|
||||
"""Extract conversation messages after a certain line number."""
|
||||
result = []
|
||||
for msg in messages:
|
||||
if msg['_line_num'] <= after_line:
|
||||
continue
|
||||
|
||||
msg_type = msg.get('type')
|
||||
is_meta = msg.get('isMeta', False)
|
||||
|
||||
if msg_type == 'user' and not is_meta:
|
||||
content = msg.get('message', {}).get('content', '')
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get('type') == 'text':
|
||||
content = item.get('text', '')
|
||||
break
|
||||
else:
|
||||
content = ''
|
||||
|
||||
if content and isinstance(content, str):
|
||||
if content.startswith(('<local-command', '<command-', '<task-notification')):
|
||||
continue
|
||||
if len(content) > 20:
|
||||
result.append({'role': 'user', 'content': content, 'line': msg['_line_num']})
|
||||
|
||||
elif msg_type == 'assistant':
|
||||
msg_content = msg.get('message', {}).get('content', '')
|
||||
text_content = ''
|
||||
tool_uses = []
|
||||
|
||||
if isinstance(msg_content, str):
|
||||
text_content = msg_content
|
||||
elif isinstance(msg_content, list):
|
||||
for item in msg_content:
|
||||
if item.get('type') == 'text':
|
||||
text_content = item.get('text', '')
|
||||
elif item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
if tool_name == 'Edit':
|
||||
tool_uses.append(f"Edit: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Write':
|
||||
tool_uses.append(f"Write: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Bash':
|
||||
cmd = tool_input.get('command', '')[:80]
|
||||
tool_uses.append(f"Bash: {cmd}")
|
||||
else:
|
||||
tool_uses.append(f"{tool_name}")
|
||||
|
||||
if text_content or tool_uses:
|
||||
result.append({
|
||||
'role': 'assistant',
|
||||
'content': text_content[:600] if text_content else '',
|
||||
'tools': tool_uses,
|
||||
'line': msg['_line_num']
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
project_path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
||||
project_dir = get_project_dir(project_path)
|
||||
|
||||
# Check if planning files exist (indicates active task)
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise.
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# No previous sessions, nothing to catch up on
|
||||
return
|
||||
|
||||
sessions = get_sessions_sorted(project_dir)
|
||||
if len(sessions) < 1:
|
||||
return
|
||||
|
||||
# Find a substantial previous session
|
||||
target_session = None
|
||||
for session in sessions:
|
||||
if session.stat().st_size > 5000:
|
||||
target_session = session
|
||||
break
|
||||
|
||||
if not target_session:
|
||||
return
|
||||
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
return
|
||||
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
if not messages_after:
|
||||
return
|
||||
|
||||
# Output catchup report
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
if msg['role'] == 'user':
|
||||
print(f"USER: {msg['content'][:300]}")
|
||||
else:
|
||||
if msg.get('content'):
|
||||
print(f"CLAUDE: {msg['content'][:300]}")
|
||||
if msg.get('tools'):
|
||||
print(f" Tools: {', '.join(msg['tools'][:4])}")
|
||||
|
||||
print("\n--- RECOMMENDED ---")
|
||||
print("1. Run: git diff --stat")
|
||||
print("2. Read: task_plan.md, progress.md, findings.md")
|
||||
print("3. Update planning files based on above context")
|
||||
print("4. Continue with task")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"sessionStart": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ".github/hooks/scripts/session-start.sh",
|
||||
"powershell": ".github/hooks/scripts/session-start.ps1",
|
||||
"timeout": 15
|
||||
}
|
||||
],
|
||||
"preToolUse": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ".github/hooks/scripts/pre-tool-use.sh",
|
||||
"powershell": ".github/hooks/scripts/pre-tool-use.ps1",
|
||||
"timeout": 5
|
||||
}
|
||||
],
|
||||
"postToolUse": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ".github/hooks/scripts/post-tool-use.sh",
|
||||
"powershell": ".github/hooks/scripts/post-tool-use.ps1",
|
||||
"timeout": 5
|
||||
}
|
||||
],
|
||||
"agentStop": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ".github/hooks/scripts/agent-stop.sh",
|
||||
"powershell": ".github/hooks/scripts/agent-stop.ps1",
|
||||
"timeout": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# planning-with-files: Agent stop hook for GitHub Copilot (PowerShell)
|
||||
# Checks if all phases in task_plan.md are complete.
|
||||
# Injects continuation context if phases are incomplete.
|
||||
# Always exits 0 — outputs JSON to stdout.
|
||||
|
||||
# Read stdin (required — Copilot pipes JSON to stdin)
|
||||
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
||||
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
||||
$InputData = [Console]::In.ReadToEnd()
|
||||
|
||||
$PlanFile = "task_plan.md"
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Output '{}'
|
||||
exit 0
|
||||
}
|
||||
|
||||
$content = Get-Content $PlanFile -Raw -Encoding UTF8
|
||||
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
# Fallback: check for [complete] inline format
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Output '{}'
|
||||
exit 0
|
||||
}
|
||||
|
||||
$msg = "[planning-with-files] Task incomplete ($COMPLETE/$TOTAL phases done). Read task_plan.md and continue working on the remaining phases."
|
||||
$output = @{
|
||||
hookSpecificOutput = @{
|
||||
hookEventName = "AgentStop"
|
||||
additionalContext = $msg
|
||||
}
|
||||
}
|
||||
$output | ConvertTo-Json -Depth 3 -Compress
|
||||
exit 0
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
# planning-with-files: Agent stop hook for GitHub Copilot
|
||||
# Checks if all phases in task_plan.md are complete.
|
||||
# Injects continuation context if phases are incomplete.
|
||||
# Always exits 0 — outputs JSON to stdout.
|
||||
|
||||
# Read stdin (required — Copilot pipes JSON to stdin)
|
||||
INPUT=$(cat)
|
||||
|
||||
PLAN_FILE="task_plan.md"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
MSG="[planning-with-files] Task incomplete ($COMPLETE/$TOTAL phases done). Read task_plan.md and continue working on the remaining phases."
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"AgentStop\",\"additionalContext\":\"$MSG\"}}"
|
||||
exit 0
|
||||
@@ -0,0 +1,17 @@
|
||||
# planning-with-files: Post-tool-use hook for GitHub Copilot (PowerShell)
|
||||
# Reminds the agent to update task_plan.md after tool use.
|
||||
# Always exits 0 — outputs JSON to stdout.
|
||||
|
||||
# Read stdin (required — Copilot pipes JSON to stdin)
|
||||
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
$InputData = [Console]::In.ReadToEnd()
|
||||
|
||||
$output = @{
|
||||
hookSpecificOutput = @{
|
||||
hookEventName = "PostToolUse"
|
||||
additionalContext = "[planning-with-files] File updated. If this completes a phase, update task_plan.md status."
|
||||
}
|
||||
}
|
||||
$output | ConvertTo-Json -Depth 3 -Compress
|
||||
exit 0
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# planning-with-files: Post-tool-use hook for GitHub Copilot
|
||||
# Reminds the agent to update task_plan.md after tool use.
|
||||
# Always exits 0 — outputs JSON to stdout.
|
||||
|
||||
# Read stdin (required — Copilot pipes JSON to stdin)
|
||||
INPUT=$(cat)
|
||||
|
||||
echo '{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"[planning-with-files] File updated. If this completes a phase, update task_plan.md status."}}'
|
||||
exit 0
|
||||
@@ -0,0 +1,33 @@
|
||||
# planning-with-files: Pre-tool-use hook for GitHub Copilot (PowerShell)
|
||||
# Reads the first 30 lines of task_plan.md to keep goals in context.
|
||||
# Always allows tool execution — this hook never blocks tools.
|
||||
# Always exits 0 — outputs JSON to stdout.
|
||||
|
||||
# Read stdin (required — Copilot pipes JSON to stdin)
|
||||
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
||||
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
||||
$InputData = [Console]::In.ReadToEnd()
|
||||
|
||||
$PlanFile = "task_plan.md"
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Output '{}'
|
||||
exit 0
|
||||
}
|
||||
|
||||
$Context = (Get-Content $PlanFile -TotalCount 30 -Encoding UTF8 -ErrorAction SilentlyContinue) -join "`n"
|
||||
|
||||
if (-not $Context) {
|
||||
Write-Output '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
||||
exit 0
|
||||
}
|
||||
|
||||
$output = @{
|
||||
hookSpecificOutput = @{
|
||||
hookEventName = "PreToolUse"
|
||||
permissionDecision = "allow"
|
||||
additionalContext = $Context
|
||||
}
|
||||
}
|
||||
$output | ConvertTo-Json -Depth 3 -Compress
|
||||
exit 0
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
# planning-with-files: Pre-tool-use hook for GitHub Copilot
|
||||
# Reads the first 30 lines of task_plan.md to keep goals in context.
|
||||
# Always allows tool execution — this hook never blocks tools.
|
||||
# Always exits 0 — outputs JSON to stdout.
|
||||
|
||||
# Read stdin (required — Copilot pipes JSON to stdin)
|
||||
INPUT=$(cat)
|
||||
|
||||
PLAN_FILE="task_plan.md"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CONTEXT=$(head -30 "$PLAN_FILE" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$CONTEXT" ]; then
|
||||
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Escape context for JSON
|
||||
PYTHON=$(command -v python3 || command -v python)
|
||||
ESCAPED=$(echo "$CONTEXT" | $PYTHON -c "import sys,json; print(json.dumps(sys.stdin.read(), ensure_ascii=False))" 2>/dev/null || echo "\"\"")
|
||||
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"allow\",\"additionalContext\":$ESCAPED}}"
|
||||
exit 0
|
||||
@@ -0,0 +1,50 @@
|
||||
# planning-with-files: Session start hook for GitHub Copilot (PowerShell)
|
||||
# When task_plan.md exists: runs session-catchup or reads plan header.
|
||||
# When task_plan.md doesn't exist: injects SKILL.md so Copilot knows the planning workflow.
|
||||
# Always exits 0 — outputs JSON to stdout.
|
||||
|
||||
# Read stdin (required — Copilot pipes JSON to stdin)
|
||||
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
||||
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
||||
$InputData = [Console]::In.ReadToEnd()
|
||||
|
||||
$PlanFile = "task_plan.md"
|
||||
$SkillDir = ".github/skills/planning-with-files"
|
||||
|
||||
if (Test-Path $PlanFile) {
|
||||
# Plan exists — try session catchup, fall back to reading plan header
|
||||
$Catchup = ""
|
||||
if (Test-Path "$SkillDir/scripts/session-catchup.py") {
|
||||
try {
|
||||
$PythonCmd = if (Get-Command python3 -ErrorAction SilentlyContinue) { "python3" } else { "python" }
|
||||
$Catchup = & $PythonCmd "$SkillDir/scripts/session-catchup.py" (Get-Location).Path 2>$null
|
||||
} catch {
|
||||
$Catchup = ""
|
||||
}
|
||||
}
|
||||
|
||||
if ($Catchup) {
|
||||
$Context = $Catchup -join "`n"
|
||||
} else {
|
||||
$Context = (Get-Content $PlanFile -TotalCount 5 -Encoding UTF8 -ErrorAction SilentlyContinue) -join "`n"
|
||||
}
|
||||
} else {
|
||||
# No plan yet — inject SKILL.md so Copilot knows the planning workflow and templates
|
||||
if (Test-Path "$SkillDir/SKILL.md") {
|
||||
$Context = Get-Content "$SkillDir/SKILL.md" -Raw -Encoding UTF8 -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $Context) {
|
||||
Write-Output '{}'
|
||||
exit 0
|
||||
}
|
||||
|
||||
$output = @{
|
||||
hookSpecificOutput = @{
|
||||
hookEventName = "SessionStart"
|
||||
additionalContext = $Context
|
||||
}
|
||||
}
|
||||
$output | ConvertTo-Json -Depth 3 -Compress
|
||||
exit 0
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# planning-with-files: Session start hook for GitHub Copilot
|
||||
# When task_plan.md exists: runs session-catchup or reads plan header.
|
||||
# When task_plan.md doesn't exist: injects SKILL.md so Copilot knows the planning workflow.
|
||||
# Always exits 0 — outputs JSON to stdout.
|
||||
|
||||
# Read stdin (required — Copilot pipes JSON to stdin)
|
||||
INPUT=$(cat)
|
||||
|
||||
PLAN_FILE="task_plan.md"
|
||||
SKILL_DIR=".github/skills/planning-with-files"
|
||||
PYTHON=$(command -v python3 || command -v python)
|
||||
|
||||
if [ -f "$PLAN_FILE" ]; then
|
||||
# Plan exists — try session catchup, fall back to reading plan header
|
||||
CATCHUP=""
|
||||
if [ -n "$PYTHON" ] && [ -f "$SKILL_DIR/scripts/session-catchup.py" ]; then
|
||||
CATCHUP=$($PYTHON "$SKILL_DIR/scripts/session-catchup.py" "$(pwd)" 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ -n "$CATCHUP" ]; then
|
||||
CONTEXT="$CATCHUP"
|
||||
else
|
||||
CONTEXT=$(head -5 "$PLAN_FILE" 2>/dev/null || echo "")
|
||||
fi
|
||||
else
|
||||
# No plan yet — inject SKILL.md so Copilot knows the planning workflow and templates
|
||||
if [ -f "$SKILL_DIR/SKILL.md" ]; then
|
||||
CONTEXT=$(cat "$SKILL_DIR/SKILL.md" 2>/dev/null || echo "")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$CONTEXT" ]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Escape context for JSON
|
||||
ESCAPED=$(echo "$CONTEXT" | $PYTHON -c "import sys,json; print(json.dumps(sys.stdin.read(), ensure_ascii=False))" 2>/dev/null || echo "\"\"")
|
||||
|
||||
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":$ESCAPED}}"
|
||||
exit 0
|
||||
@@ -21,6 +21,14 @@ notes.md
|
||||
!examples/**/*.md
|
||||
!**/templates/*.md
|
||||
|
||||
# ClawdHub publish folder (managed separately)
|
||||
clawdhub-publish/
|
||||
|
||||
# Claude session files
|
||||
.claude/
|
||||
|
||||
# Keep the skill folder clean
|
||||
*.log
|
||||
*.tmp
|
||||
WIKI_HOME_PAGE.md
|
||||
DISCUSSION_2_CONTENT.md
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.10.0"
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls. Now with automatic session recovery after /clear.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
user-invocable: true
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Bash
|
||||
- Glob
|
||||
- Grep
|
||||
- WebFetch
|
||||
- WebSearch
|
||||
allowed-tools: "Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch"
|
||||
hooks:
|
||||
PreToolUse:
|
||||
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
|
||||
@@ -27,7 +18,7 @@ hooks:
|
||||
- hooks:
|
||||
- type: command
|
||||
command: |
|
||||
SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/planning-with-files}/scripts"
|
||||
SCRIPT_DIR="${KILOCODE_SKILL_ROOT:-$HOME/.kilocode/skills/planning-with-files}/scripts"
|
||||
|
||||
IS_WINDOWS=0
|
||||
if [ "${OS-}" = "Windows_NT" ]; then
|
||||
@@ -51,6 +42,8 @@ hooks:
|
||||
else
|
||||
sh "$SCRIPT_DIR/check-complete.sh"
|
||||
fi
|
||||
metadata:
|
||||
version: "2.16.1"
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
@@ -63,7 +56,7 @@ Work like Manus: Use persistent markdown files as your "working memory on disk."
|
||||
|
||||
```bash
|
||||
# Linux/macOS (auto-detects python3 or python)
|
||||
$(command -v python3 || command -v python) ${CLAUDE_PLUGIN_ROOT}/scripts/session-catchup.py "$(pwd)"
|
||||
$(command -v python3 || command -v python) ~/.kilocode/skills/planning-with-files/scripts/session-catchup.py "$(pwd)"
|
||||
```
|
||||
|
||||
```powershell
|
||||
@@ -79,12 +72,12 @@ If catchup report shows unsynced context:
|
||||
|
||||
## Important: Where Files Go
|
||||
|
||||
- **Templates** are in `${CLAUDE_PLUGIN_ROOT}/templates/`
|
||||
- **Templates** are in `~/.kilocode/skills/planning-with-files/templates/`
|
||||
- **Your planning files** go in **your project directory**
|
||||
|
||||
| Location | What Goes There |
|
||||
|----------|-----------------|
|
||||
| Skill directory (`${CLAUDE_PLUGIN_ROOT}/`) | Templates, scripts, reference docs |
|
||||
| Skill directory (`~/.kilocode/skills/planning-with-files/`) | Templates, scripts, reference docs |
|
||||
| Your project directory | `task_plan.md`, `findings.md`, `progress.md` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "ERROR: $PlanFile not found"
|
||||
Write-Host "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "=== Task Completion Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count phases by status
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
Write-Host "Total phases: $TOTAL"
|
||||
Write-Host "Complete: $COMPLETE"
|
||||
Write-Host "In progress: $IN_PROGRESS"
|
||||
Write-Host "Pending: $PENDING"
|
||||
Write-Host ""
|
||||
|
||||
# Check completion
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "TASK NOT COMPLETE"
|
||||
Write-Host ""
|
||||
Write-Host "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "ERROR: $PLAN_FILE not found"
|
||||
echo "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== Task Completion Check ==="
|
||||
echo ""
|
||||
|
||||
# Count phases by status (using -F for fixed string matching)
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
echo "Total phases: $TOTAL"
|
||||
echo "Complete: $COMPLETE"
|
||||
echo "In progress: $IN_PROGRESS"
|
||||
echo "Pending: $PENDING"
|
||||
echo ""
|
||||
|
||||
# Check completion
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "TASK NOT COMPLETE"
|
||||
echo ""
|
||||
echo "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"PreToolUse": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "cat task_plan.md 2>/dev/null | head -30 || true",
|
||||
"matcher": { "tool_name": "Write|Edit|Bash|Read|Glob|Grep" },
|
||||
"timeout": 5000,
|
||||
"description": "Read plan before tool use to keep goals in active context"
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "echo '[planning-with-files] File updated. If this completes a phase, update task_plan.md status.'",
|
||||
"matcher": { "tool_name": "Write|Edit" },
|
||||
"description": "Remind agent to update plan status after file changes"
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "sh .mastracode/skills/planning-with-files/scripts/check-complete.sh 2>/dev/null || sh ~/.mastracode/skills/planning-with-files/scripts/check-complete.sh 2>/dev/null || true",
|
||||
"timeout": 10000,
|
||||
"description": "Check all phases are complete before the agent stops"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
user-invocable: true
|
||||
allowed-tools: "Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch"
|
||||
hooks:
|
||||
PreToolUse:
|
||||
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
|
||||
hooks:
|
||||
- type: command
|
||||
command: "cat task_plan.md 2>/dev/null | head -30 || true"
|
||||
PostToolUse:
|
||||
- matcher: "Write|Edit"
|
||||
hooks:
|
||||
- type: command
|
||||
command: "echo '[planning-with-files] File updated. If this completes a phase, update task_plan.md status.'"
|
||||
Stop:
|
||||
- hooks:
|
||||
- type: command
|
||||
command: |
|
||||
SCRIPT_DIR="${HOME}/.mastracode/skills/planning-with-files/scripts"
|
||||
[ -f "$SCRIPT_DIR/check-complete.sh" ] || SCRIPT_DIR=".mastracode/skills/planning-with-files/scripts"
|
||||
|
||||
IS_WINDOWS=0
|
||||
if [ "${OS-}" = "Windows_NT" ]; then
|
||||
IS_WINDOWS=1
|
||||
else
|
||||
UNAME_S="$(uname -s 2>/dev/null || echo '')"
|
||||
case "$UNAME_S" in
|
||||
CYGWIN*|MINGW*|MSYS*) IS_WINDOWS=1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$IS_WINDOWS" -eq 1 ]; then
|
||||
if command -v pwsh >/dev/null 2>&1; then
|
||||
pwsh -ExecutionPolicy Bypass -File "$SCRIPT_DIR/check-complete.ps1" 2>/dev/null ||
|
||||
powershell -ExecutionPolicy Bypass -File "$SCRIPT_DIR/check-complete.ps1" 2>/dev/null ||
|
||||
sh "$SCRIPT_DIR/check-complete.sh"
|
||||
else
|
||||
powershell -ExecutionPolicy Bypass -File "$SCRIPT_DIR/check-complete.ps1" 2>/dev/null ||
|
||||
sh "$SCRIPT_DIR/check-complete.sh"
|
||||
fi
|
||||
else
|
||||
sh "$SCRIPT_DIR/check-complete.sh"
|
||||
fi
|
||||
metadata:
|
||||
version: "2.18.1"
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
Work like Manus: Use persistent markdown files as your "working memory on disk."
|
||||
|
||||
## FIRST: Check for Previous Session (v2.2.0)
|
||||
|
||||
**Before starting work**, check for unsynced context from a previous session:
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
$(command -v python3 || command -v python) ~/.mastracode/skills/planning-with-files/scripts/session-catchup.py "$(pwd)"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# Windows PowerShell
|
||||
& (Get-Command python -ErrorAction SilentlyContinue).Source "$env:USERPROFILE\.mastracode\skills\planning-with-files\scripts\session-catchup.py" (Get-Location)
|
||||
```
|
||||
|
||||
If catchup report shows unsynced context:
|
||||
1. Run `git diff --stat` to see actual code changes
|
||||
2. Read current planning files
|
||||
3. Update planning files based on catchup + git diff
|
||||
4. Then proceed with task
|
||||
|
||||
## Important: Where Files Go
|
||||
|
||||
- **Templates** are in this skill's `templates/` folder
|
||||
- **Your planning files** go in **your project directory**
|
||||
|
||||
| Location | What Goes There |
|
||||
|----------|-----------------|
|
||||
| Skill directory | Templates, scripts, reference docs |
|
||||
| Your project directory | `task_plan.md`, `findings.md`, `progress.md` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
Before ANY complex task:
|
||||
|
||||
1. **Create `task_plan.md`** — Use [templates/task_plan.md](templates/task_plan.md) as reference
|
||||
2. **Create `findings.md`** — Use [templates/findings.md](templates/findings.md) as reference
|
||||
3. **Create `progress.md`** — Use [templates/progress.md](templates/progress.md) as reference
|
||||
4. **Re-read plan before decisions** — Refreshes goals in attention window
|
||||
5. **Update after each phase** — Mark complete, log errors
|
||||
|
||||
> **Note:** Planning files go in your project root, not the skill installation folder.
|
||||
|
||||
## The Core Pattern
|
||||
|
||||
```
|
||||
Context Window = RAM (volatile, limited)
|
||||
Filesystem = Disk (persistent, unlimited)
|
||||
|
||||
→ Anything important gets written to disk.
|
||||
```
|
||||
|
||||
## File Purposes
|
||||
|
||||
| File | Purpose | When to Update |
|
||||
|------|---------|----------------|
|
||||
| `task_plan.md` | Phases, progress, decisions | After each phase |
|
||||
| `findings.md` | Research, discoveries | After ANY discovery |
|
||||
| `progress.md` | Session log, test results | Throughout session |
|
||||
|
||||
## Critical Rules
|
||||
|
||||
### 1. Create Plan First
|
||||
Never start a complex task without `task_plan.md`. Non-negotiable.
|
||||
|
||||
### 2. The 2-Action Rule
|
||||
> "After every 2 view/browser/search operations, IMMEDIATELY save key findings to text files."
|
||||
|
||||
This prevents visual/multimodal information from being lost.
|
||||
|
||||
### 3. Read Before Decide
|
||||
Before major decisions, read the plan file. This keeps goals in your attention window.
|
||||
|
||||
### 4. Update After Act
|
||||
After completing any phase:
|
||||
- Mark phase status: `in_progress` → `complete`
|
||||
- Log any errors encountered
|
||||
- Note files created/modified
|
||||
|
||||
### 5. Log ALL Errors
|
||||
Every error goes in the plan file. This builds knowledge and prevents repetition.
|
||||
|
||||
```markdown
|
||||
## Errors Encountered
|
||||
| Error | Attempt | Resolution |
|
||||
|-------|---------|------------|
|
||||
| FileNotFoundError | 1 | Created default config |
|
||||
| API timeout | 2 | Added retry logic |
|
||||
```
|
||||
|
||||
### 6. Never Repeat Failures
|
||||
```
|
||||
if action_failed:
|
||||
next_action != same_action
|
||||
```
|
||||
Track what you tried. Mutate the approach.
|
||||
|
||||
## The 3-Strike Error Protocol
|
||||
|
||||
```
|
||||
ATTEMPT 1: Diagnose & Fix
|
||||
→ Read error carefully
|
||||
→ Identify root cause
|
||||
→ Apply targeted fix
|
||||
|
||||
ATTEMPT 2: Alternative Approach
|
||||
→ Same error? Try different method
|
||||
→ Different tool? Different library?
|
||||
→ NEVER repeat exact same failing action
|
||||
|
||||
ATTEMPT 3: Broader Rethink
|
||||
→ Question assumptions
|
||||
→ Search for solutions
|
||||
→ Consider updating the plan
|
||||
|
||||
AFTER 3 FAILURES: Escalate to User
|
||||
→ Explain what you tried
|
||||
→ Share the specific error
|
||||
→ Ask for guidance
|
||||
```
|
||||
|
||||
## Read vs Write Decision Matrix
|
||||
|
||||
| Situation | Action | Reason |
|
||||
|-----------|--------|--------|
|
||||
| Just wrote a file | DON'T read | Content still in context |
|
||||
| Viewed image/PDF | Write findings NOW | Multimodal → text before lost |
|
||||
| Browser returned data | Write to file | Screenshots don't persist |
|
||||
| Starting new phase | Read plan/findings | Re-orient if context stale |
|
||||
| Error occurred | Read relevant file | Need current state to fix |
|
||||
| Resuming after gap | Read all planning files | Recover state |
|
||||
|
||||
## The 5-Question Reboot Test
|
||||
|
||||
If you can answer these, your context management is solid:
|
||||
|
||||
| Question | Answer Source |
|
||||
|----------|---------------|
|
||||
| Where am I? | Current phase in task_plan.md |
|
||||
| Where am I going? | Remaining phases |
|
||||
| What's the goal? | Goal statement in plan |
|
||||
| What have I learned? | findings.md |
|
||||
| What have I done? | progress.md |
|
||||
|
||||
## When to Use This Pattern
|
||||
|
||||
**Use for:**
|
||||
- Multi-step tasks (3+ steps)
|
||||
- Research tasks
|
||||
- Building/creating projects
|
||||
- Tasks spanning many tool calls
|
||||
- Anything requiring organization
|
||||
|
||||
**Skip for:**
|
||||
- Simple questions
|
||||
- Single-file edits
|
||||
- Quick lookups
|
||||
|
||||
## Templates
|
||||
|
||||
Copy these templates to start:
|
||||
|
||||
- [templates/task_plan.md](templates/task_plan.md) — Phase tracking
|
||||
- [templates/findings.md](templates/findings.md) — Research storage
|
||||
- [templates/progress.md](templates/progress.md) — Session logging
|
||||
|
||||
## Scripts
|
||||
|
||||
Helper scripts for automation:
|
||||
|
||||
- `scripts/init-session.sh` — Initialize all planning files
|
||||
- `scripts/check-complete.sh` — Verify all phases complete
|
||||
- `scripts/session-catchup.py` — Recover context from previous session (v2.2.0)
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
- **Manus Principles:** See [references/reference.md](references/reference.md)
|
||||
- **Real Examples:** See [references/examples.md](references/examples.md)
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
| Don't | Do Instead |
|
||||
|-------|------------|
|
||||
| Use TodoWrite for persistence | Create task_plan.md file |
|
||||
| State goals once and forget | Re-read plan before decisions |
|
||||
| Hide errors and retry silently | Log errors to plan file |
|
||||
| Stuff everything in context | Store large content in files |
|
||||
| Start executing immediately | Create plan file FIRST |
|
||||
| Repeat failed actions | Track attempts, mutate approach |
|
||||
| Create files in skill directory | Create files in your project |
|
||||
@@ -0,0 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Session Catchup Script for planning-with-files
|
||||
|
||||
Analyzes the previous session to find unsynced context after the last
|
||||
planning file update. Designed to run on SessionStart.
|
||||
|
||||
Usage: python3 session-catchup.py [project-path]
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
from datetime import datetime
|
||||
|
||||
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
|
||||
|
||||
|
||||
def get_project_dir(project_path: str) -> Path:
|
||||
"""Convert project path to Claude's storage path format."""
|
||||
sanitized = project_path.replace('/', '-')
|
||||
if not sanitized.startswith('-'):
|
||||
sanitized = '-' + sanitized
|
||||
sanitized = sanitized.replace('_', '-')
|
||||
return Path.home() / '.claude' / 'projects' / sanitized
|
||||
|
||||
|
||||
def get_sessions_sorted(project_dir: Path) -> List[Path]:
|
||||
"""Get all session files sorted by modification time (newest first)."""
|
||||
sessions = list(project_dir.glob('*.jsonl'))
|
||||
main_sessions = [s for s in sessions if not s.name.startswith('agent-')]
|
||||
return sorted(main_sessions, key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
|
||||
|
||||
def parse_session_messages(session_file: Path) -> List[Dict]:
|
||||
"""Parse all messages from a session file, preserving order."""
|
||||
messages = []
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
try:
|
||||
data = json.loads(line)
|
||||
data['_line_num'] = line_num
|
||||
messages.append(data)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return messages
|
||||
|
||||
|
||||
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
|
||||
"""
|
||||
Find the last time a planning file was written/edited.
|
||||
Returns (line_number, filename) or (-1, None) if not found.
|
||||
"""
|
||||
last_update_line = -1
|
||||
last_update_file = None
|
||||
|
||||
for msg in messages:
|
||||
msg_type = msg.get('type')
|
||||
|
||||
if msg_type == 'assistant':
|
||||
content = msg.get('message', {}).get('content', [])
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
|
||||
if tool_name in ('Write', 'Edit'):
|
||||
file_path = tool_input.get('file_path', '')
|
||||
for pf in PLANNING_FILES:
|
||||
if file_path.endswith(pf):
|
||||
last_update_line = msg['_line_num']
|
||||
last_update_file = pf
|
||||
|
||||
return last_update_line, last_update_file
|
||||
|
||||
|
||||
def extract_messages_after(messages: List[Dict], after_line: int) -> List[Dict]:
|
||||
"""Extract conversation messages after a certain line number."""
|
||||
result = []
|
||||
for msg in messages:
|
||||
if msg['_line_num'] <= after_line:
|
||||
continue
|
||||
|
||||
msg_type = msg.get('type')
|
||||
is_meta = msg.get('isMeta', False)
|
||||
|
||||
if msg_type == 'user' and not is_meta:
|
||||
content = msg.get('message', {}).get('content', '')
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get('type') == 'text':
|
||||
content = item.get('text', '')
|
||||
break
|
||||
else:
|
||||
content = ''
|
||||
|
||||
if content and isinstance(content, str):
|
||||
if content.startswith(('<local-command', '<command-', '<task-notification')):
|
||||
continue
|
||||
if len(content) > 20:
|
||||
result.append({'role': 'user', 'content': content, 'line': msg['_line_num']})
|
||||
|
||||
elif msg_type == 'assistant':
|
||||
msg_content = msg.get('message', {}).get('content', '')
|
||||
text_content = ''
|
||||
tool_uses = []
|
||||
|
||||
if isinstance(msg_content, str):
|
||||
text_content = msg_content
|
||||
elif isinstance(msg_content, list):
|
||||
for item in msg_content:
|
||||
if item.get('type') == 'text':
|
||||
text_content = item.get('text', '')
|
||||
elif item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
if tool_name == 'Edit':
|
||||
tool_uses.append(f"Edit: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Write':
|
||||
tool_uses.append(f"Write: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Bash':
|
||||
cmd = tool_input.get('command', '')[:80]
|
||||
tool_uses.append(f"Bash: {cmd}")
|
||||
else:
|
||||
tool_uses.append(f"{tool_name}")
|
||||
|
||||
if text_content or tool_uses:
|
||||
result.append({
|
||||
'role': 'assistant',
|
||||
'content': text_content[:600] if text_content else '',
|
||||
'tools': tool_uses,
|
||||
'line': msg['_line_num']
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
project_path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
||||
project_dir = get_project_dir(project_path)
|
||||
|
||||
# Check if planning files exist (indicates active task)
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise.
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# No previous sessions, nothing to catch up on
|
||||
return
|
||||
|
||||
sessions = get_sessions_sorted(project_dir)
|
||||
if len(sessions) < 1:
|
||||
return
|
||||
|
||||
# Find a substantial previous session
|
||||
target_session = None
|
||||
for session in sessions:
|
||||
if session.stat().st_size > 5000:
|
||||
target_session = session
|
||||
break
|
||||
|
||||
if not target_session:
|
||||
return
|
||||
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
return
|
||||
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
if not messages_after:
|
||||
return
|
||||
|
||||
# Output catchup report
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
if msg['role'] == 'user':
|
||||
print(f"USER: {msg['content'][:300]}")
|
||||
else:
|
||||
if msg.get('content'):
|
||||
print(f"CLAUDE: {msg['content'][:300]}")
|
||||
if msg.get('tools'):
|
||||
print(f" Tools: {', '.join(msg['tools'][:4])}")
|
||||
|
||||
print("\n--- RECOMMENDED ---")
|
||||
print("1. Run: git diff --stat")
|
||||
print("2. Read: task_plan.md, progress.md, findings.md")
|
||||
print("3. Update planning files based on above context")
|
||||
print("4. Continue with task")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,95 @@
|
||||
# Findings & Decisions
|
||||
<!--
|
||||
WHAT: Your knowledge base for the task. Stores everything you discover and decide.
|
||||
WHY: Context windows are limited. This file is your "external memory" - persistent and unlimited.
|
||||
WHEN: Update after ANY discovery, especially after 2 view/browser/search operations (2-Action Rule).
|
||||
-->
|
||||
|
||||
## Requirements
|
||||
<!--
|
||||
WHAT: What the user asked for, broken down into specific requirements.
|
||||
WHY: Keeps requirements visible so you don't forget what you're building.
|
||||
WHEN: Fill this in during Phase 1 (Requirements & Discovery).
|
||||
EXAMPLE:
|
||||
- Command-line interface
|
||||
- Add tasks
|
||||
- List all tasks
|
||||
- Delete tasks
|
||||
- Python implementation
|
||||
-->
|
||||
<!-- Captured from user request -->
|
||||
-
|
||||
|
||||
## Research Findings
|
||||
<!--
|
||||
WHAT: Key discoveries from web searches, documentation reading, or exploration.
|
||||
WHY: Multimodal content (images, browser results) doesn't persist. Write it down immediately.
|
||||
WHEN: After EVERY 2 view/browser/search operations, update this section (2-Action Rule).
|
||||
EXAMPLE:
|
||||
- Python's argparse module supports subcommands for clean CLI design
|
||||
- JSON module handles file persistence easily
|
||||
- Standard pattern: python script.py <command> [args]
|
||||
-->
|
||||
<!-- Key discoveries during exploration -->
|
||||
-
|
||||
|
||||
## Technical Decisions
|
||||
<!--
|
||||
WHAT: Architecture and implementation choices you've made, with reasoning.
|
||||
WHY: You'll forget why you chose a technology or approach. This table preserves that knowledge.
|
||||
WHEN: Update whenever you make a significant technical choice.
|
||||
EXAMPLE:
|
||||
| Use JSON for storage | Simple, human-readable, built-in Python support |
|
||||
| argparse with subcommands | Clean CLI: python todo.py add "task" |
|
||||
-->
|
||||
<!-- Decisions made with rationale -->
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| | |
|
||||
|
||||
## Issues Encountered
|
||||
<!--
|
||||
WHAT: Problems you ran into and how you solved them.
|
||||
WHY: Similar to errors in task_plan.md, but focused on broader issues (not just code errors).
|
||||
WHEN: Document when you encounter blockers or unexpected challenges.
|
||||
EXAMPLE:
|
||||
| Empty file causes JSONDecodeError | Added explicit empty file check before json.load() |
|
||||
-->
|
||||
<!-- Errors and how they were resolved -->
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| | |
|
||||
|
||||
## Resources
|
||||
<!--
|
||||
WHAT: URLs, file paths, API references, documentation links you've found useful.
|
||||
WHY: Easy reference for later. Don't lose important links in context.
|
||||
WHEN: Add as you discover useful resources.
|
||||
EXAMPLE:
|
||||
- Python argparse docs: https://docs.python.org/3/library/argparse.html
|
||||
- Project structure: src/main.py, src/utils.py
|
||||
-->
|
||||
<!-- URLs, file paths, API references -->
|
||||
-
|
||||
|
||||
## Visual/Browser Findings
|
||||
<!--
|
||||
WHAT: Information you learned from viewing images, PDFs, or browser results.
|
||||
WHY: CRITICAL - Visual/multimodal content doesn't persist in context. Must be captured as text.
|
||||
WHEN: IMMEDIATELY after viewing images or browser results. Don't wait!
|
||||
EXAMPLE:
|
||||
- Screenshot shows login form has email and password fields
|
||||
- Browser shows API returns JSON with "status" and "data" keys
|
||||
-->
|
||||
<!-- CRITICAL: Update after every 2 view/browser operations -->
|
||||
<!-- Multimodal content must be captured as text immediately -->
|
||||
-
|
||||
|
||||
---
|
||||
<!--
|
||||
REMINDER: The 2-Action Rule
|
||||
After every 2 view/browser/search operations, you MUST update this file.
|
||||
This prevents visual information from being lost when context resets.
|
||||
-->
|
||||
*Update this file after every 2 view/browser/search operations*
|
||||
*This prevents visual information from being lost*
|
||||
@@ -0,0 +1,114 @@
|
||||
# Progress Log
|
||||
<!--
|
||||
WHAT: Your session log - a chronological record of what you did, when, and what happened.
|
||||
WHY: Answers "What have I done?" in the 5-Question Reboot Test. Helps you resume after breaks.
|
||||
WHEN: Update after completing each phase or encountering errors. More detailed than task_plan.md.
|
||||
-->
|
||||
|
||||
## Session: [DATE]
|
||||
<!--
|
||||
WHAT: The date of this work session.
|
||||
WHY: Helps track when work happened, useful for resuming after time gaps.
|
||||
EXAMPLE: 2026-01-15
|
||||
-->
|
||||
|
||||
### Phase 1: [Title]
|
||||
<!--
|
||||
WHAT: Detailed log of actions taken during this phase.
|
||||
WHY: Provides context for what was done, making it easier to resume or debug.
|
||||
WHEN: Update as you work through the phase, or at least when you complete it.
|
||||
-->
|
||||
- **Status:** in_progress
|
||||
- **Started:** [timestamp]
|
||||
<!--
|
||||
STATUS: Same as task_plan.md (pending, in_progress, complete)
|
||||
TIMESTAMP: When you started this phase (e.g., "2026-01-15 10:00")
|
||||
-->
|
||||
- Actions taken:
|
||||
<!--
|
||||
WHAT: List of specific actions you performed.
|
||||
EXAMPLE:
|
||||
- Created todo.py with basic structure
|
||||
- Implemented add functionality
|
||||
- Fixed FileNotFoundError
|
||||
-->
|
||||
-
|
||||
- Files created/modified:
|
||||
<!--
|
||||
WHAT: Which files you created or changed.
|
||||
WHY: Quick reference for what was touched. Helps with debugging and review.
|
||||
EXAMPLE:
|
||||
- todo.py (created)
|
||||
- todos.json (created by app)
|
||||
- task_plan.md (updated)
|
||||
-->
|
||||
-
|
||||
|
||||
### Phase 2: [Title]
|
||||
<!--
|
||||
WHAT: Same structure as Phase 1, for the next phase.
|
||||
WHY: Keep a separate log entry for each phase to track progress clearly.
|
||||
-->
|
||||
- **Status:** pending
|
||||
- Actions taken:
|
||||
-
|
||||
- Files created/modified:
|
||||
-
|
||||
|
||||
## Test Results
|
||||
<!--
|
||||
WHAT: Table of tests you ran, what you expected, what actually happened.
|
||||
WHY: Documents verification of functionality. Helps catch regressions.
|
||||
WHEN: Update as you test features, especially during Phase 4 (Testing & Verification).
|
||||
EXAMPLE:
|
||||
| Add task | python todo.py add "Buy milk" | Task added | Task added successfully | ✓ |
|
||||
| List tasks | python todo.py list | Shows all tasks | Shows all tasks | ✓ |
|
||||
-->
|
||||
| Test | Input | Expected | Actual | Status |
|
||||
|------|-------|----------|--------|--------|
|
||||
| | | | | |
|
||||
|
||||
## Error Log
|
||||
<!--
|
||||
WHAT: Detailed log of every error encountered, with timestamps and resolution attempts.
|
||||
WHY: More detailed than task_plan.md's error table. Helps you learn from mistakes.
|
||||
WHEN: Add immediately when an error occurs, even if you fix it quickly.
|
||||
EXAMPLE:
|
||||
| 2026-01-15 10:35 | FileNotFoundError | 1 | Added file existence check |
|
||||
| 2026-01-15 10:37 | JSONDecodeError | 2 | Added empty file handling |
|
||||
-->
|
||||
<!-- Keep ALL errors - they help avoid repetition -->
|
||||
| Timestamp | Error | Attempt | Resolution |
|
||||
|-----------|-------|---------|------------|
|
||||
| | | 1 | |
|
||||
|
||||
## 5-Question Reboot Check
|
||||
<!--
|
||||
WHAT: Five questions that verify your context is solid. If you can answer these, you're on track.
|
||||
WHY: This is the "reboot test" - if you can answer all 5, you can resume work effectively.
|
||||
WHEN: Update periodically, especially when resuming after a break or context reset.
|
||||
|
||||
THE 5 QUESTIONS:
|
||||
1. Where am I? → Current phase in task_plan.md
|
||||
2. Where am I going? → Remaining phases
|
||||
3. What's the goal? → Goal statement in task_plan.md
|
||||
4. What have I learned? → See findings.md
|
||||
5. What have I done? → See progress.md (this file)
|
||||
-->
|
||||
<!-- If you can answer these, context is solid -->
|
||||
| Question | Answer |
|
||||
|----------|--------|
|
||||
| Where am I? | Phase X |
|
||||
| Where am I going? | Remaining phases |
|
||||
| What's the goal? | [goal statement] |
|
||||
| What have I learned? | See findings.md |
|
||||
| What have I done? | See above |
|
||||
|
||||
---
|
||||
<!--
|
||||
REMINDER:
|
||||
- Update after completing each phase or encountering errors
|
||||
- Be detailed - this is your "what happened" log
|
||||
- Include timestamps for errors to track when issues occurred
|
||||
-->
|
||||
*Update after completing each phase or encountering errors*
|
||||
@@ -0,0 +1,132 @@
|
||||
# Task Plan: [Brief Description]
|
||||
<!--
|
||||
WHAT: This is your roadmap for the entire task. Think of it as your "working memory on disk."
|
||||
WHY: After 50+ tool calls, your original goals can get forgotten. This file keeps them fresh.
|
||||
WHEN: Create this FIRST, before starting any work. Update after each phase completes.
|
||||
-->
|
||||
|
||||
## Goal
|
||||
<!--
|
||||
WHAT: One clear sentence describing what you're trying to achieve.
|
||||
WHY: This is your north star. Re-reading this keeps you focused on the end state.
|
||||
EXAMPLE: "Create a Python CLI todo app with add, list, and delete functionality."
|
||||
-->
|
||||
[One sentence describing the end state]
|
||||
|
||||
## Current Phase
|
||||
<!--
|
||||
WHAT: Which phase you're currently working on (e.g., "Phase 1", "Phase 3").
|
||||
WHY: Quick reference for where you are in the task. Update this as you progress.
|
||||
-->
|
||||
Phase 1
|
||||
|
||||
## Phases
|
||||
<!--
|
||||
WHAT: Break your task into 3-7 logical phases. Each phase should be completable.
|
||||
WHY: Breaking work into phases prevents overwhelm and makes progress visible.
|
||||
WHEN: Update status after completing each phase: pending → in_progress → complete
|
||||
-->
|
||||
|
||||
### Phase 1: Requirements & Discovery
|
||||
<!--
|
||||
WHAT: Understand what needs to be done and gather initial information.
|
||||
WHY: Starting without understanding leads to wasted effort. This phase prevents that.
|
||||
-->
|
||||
- [ ] Understand user intent
|
||||
- [ ] Identify constraints and requirements
|
||||
- [ ] Document findings in findings.md
|
||||
- **Status:** in_progress
|
||||
<!--
|
||||
STATUS VALUES:
|
||||
- pending: Not started yet
|
||||
- in_progress: Currently working on this
|
||||
- complete: Finished this phase
|
||||
-->
|
||||
|
||||
### Phase 2: Planning & Structure
|
||||
<!--
|
||||
WHAT: Decide how you'll approach the problem and what structure you'll use.
|
||||
WHY: Good planning prevents rework. Document decisions so you remember why you chose them.
|
||||
-->
|
||||
- [ ] Define technical approach
|
||||
- [ ] Create project structure if needed
|
||||
- [ ] Document decisions with rationale
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 3: Implementation
|
||||
<!--
|
||||
WHAT: Actually build/create/write the solution.
|
||||
WHY: This is where the work happens. Break into smaller sub-tasks if needed.
|
||||
-->
|
||||
- [ ] Execute the plan step by step
|
||||
- [ ] Write code to files before executing
|
||||
- [ ] Test incrementally
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 4: Testing & Verification
|
||||
<!--
|
||||
WHAT: Verify everything works and meets requirements.
|
||||
WHY: Catching issues early saves time. Document test results in progress.md.
|
||||
-->
|
||||
- [ ] Verify all requirements met
|
||||
- [ ] Document test results in progress.md
|
||||
- [ ] Fix any issues found
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 5: Delivery
|
||||
<!--
|
||||
WHAT: Final review and handoff to user.
|
||||
WHY: Ensures nothing is forgotten and deliverables are complete.
|
||||
-->
|
||||
- [ ] Review all output files
|
||||
- [ ] Ensure deliverables are complete
|
||||
- [ ] Deliver to user
|
||||
- **Status:** pending
|
||||
|
||||
## Key Questions
|
||||
<!--
|
||||
WHAT: Important questions you need to answer during the task.
|
||||
WHY: These guide your research and decision-making. Answer them as you go.
|
||||
EXAMPLE:
|
||||
1. Should tasks persist between sessions? (Yes - need file storage)
|
||||
2. What format for storing tasks? (JSON file)
|
||||
-->
|
||||
1. [Question to answer]
|
||||
2. [Question to answer]
|
||||
|
||||
## Decisions Made
|
||||
<!--
|
||||
WHAT: Technical and design decisions you've made, with the reasoning behind them.
|
||||
WHY: You'll forget why you made choices. This table helps you remember and justify decisions.
|
||||
WHEN: Update whenever you make a significant choice (technology, approach, structure).
|
||||
EXAMPLE:
|
||||
| Use JSON for storage | Simple, human-readable, built-in Python support |
|
||||
-->
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| | |
|
||||
|
||||
## Errors Encountered
|
||||
<!--
|
||||
WHAT: Every error you encounter, what attempt number it was, and how you resolved it.
|
||||
WHY: Logging errors prevents repeating the same mistakes. This is critical for learning.
|
||||
WHEN: Add immediately when an error occurs, even if you fix it quickly.
|
||||
EXAMPLE:
|
||||
| FileNotFoundError | 1 | Check if file exists, create empty list if not |
|
||||
| JSONDecodeError | 2 | Handle empty file case explicitly |
|
||||
-->
|
||||
| Error | Attempt | Resolution |
|
||||
|-------|---------|------------|
|
||||
| | 1 | |
|
||||
|
||||
## Notes
|
||||
<!--
|
||||
REMINDERS:
|
||||
- Update phase status as you progress: pending → in_progress → complete
|
||||
- Re-read this plan before major decisions (attention manipulation)
|
||||
- Log ALL errors - they help avoid repetition
|
||||
- Never repeat a failed action - mutate your approach instead
|
||||
-->
|
||||
- Update phase status as you progress: pending → in_progress → complete
|
||||
- Re-read this plan before major decisions (attention manipulation)
|
||||
- Log ALL errors - they help avoid repetition
|
||||
@@ -1,42 +0,0 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "ERROR: $PlanFile not found"
|
||||
Write-Host "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "=== Task Completion Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count phases by status
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
Write-Host "Total phases: $TOTAL"
|
||||
Write-Host "Complete: $COMPLETE"
|
||||
Write-Host "In progress: $IN_PROGRESS"
|
||||
Write-Host "Pending: $PENDING"
|
||||
Write-Host ""
|
||||
|
||||
# Check completion
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "TASK NOT COMPLETE"
|
||||
Write-Host ""
|
||||
Write-Host "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "ERROR: $PLAN_FILE not found"
|
||||
echo "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Task Completion Check ==="
|
||||
echo ""
|
||||
|
||||
# Count phases by status (using -F for fixed string matching)
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
echo "Total phases: $TOTAL"
|
||||
echo "Complete: $COMPLETE"
|
||||
echo "In progress: $IN_PROGRESS"
|
||||
echo "Pending: $PENDING"
|
||||
echo ""
|
||||
|
||||
# Check completion
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
else
|
||||
echo "TASK NOT COMPLETE"
|
||||
echo ""
|
||||
echo "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
fi
|
||||
+5
-3
@@ -1,10 +1,12 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.10.0"
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
homepage: https://github.com/OthmanAdi/planning-with-files
|
||||
user-invocable: true
|
||||
metadata: {"moltbot":{"os":["darwin","linux","win32"]}}
|
||||
metadata:
|
||||
version: "2.16.1"
|
||||
openclaw:
|
||||
os: ["darwin", "linux", "win32"]
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
@@ -0,0 +1,202 @@
|
||||
# Examples: Planning with Files in Action
|
||||
|
||||
## Example 1: Research Task
|
||||
|
||||
**User Request:** "Research the benefits of morning exercise and write a summary"
|
||||
|
||||
### Loop 1: Create Plan
|
||||
```bash
|
||||
Write task_plan.md
|
||||
```
|
||||
|
||||
```markdown
|
||||
# Task Plan: Morning Exercise Benefits Research
|
||||
|
||||
## Goal
|
||||
Create a research summary on the benefits of morning exercise.
|
||||
|
||||
## Phases
|
||||
- [ ] Phase 1: Create this plan ✓
|
||||
- [ ] Phase 2: Search and gather sources
|
||||
- [ ] Phase 3: Synthesize findings
|
||||
- [ ] Phase 4: Deliver summary
|
||||
|
||||
## Key Questions
|
||||
1. What are the physical health benefits?
|
||||
2. What are the mental health benefits?
|
||||
3. What scientific studies support this?
|
||||
|
||||
## Status
|
||||
**Currently in Phase 1** - Creating plan
|
||||
```
|
||||
|
||||
### Loop 2: Research
|
||||
```bash
|
||||
Read task_plan.md # Refresh goals
|
||||
WebSearch "morning exercise benefits"
|
||||
Write notes.md # Store findings
|
||||
Edit task_plan.md # Mark Phase 2 complete
|
||||
```
|
||||
|
||||
### Loop 3: Synthesize
|
||||
```bash
|
||||
Read task_plan.md # Refresh goals
|
||||
Read notes.md # Get findings
|
||||
Write morning_exercise_summary.md
|
||||
Edit task_plan.md # Mark Phase 3 complete
|
||||
```
|
||||
|
||||
### Loop 4: Deliver
|
||||
```bash
|
||||
Read task_plan.md # Verify complete
|
||||
Deliver morning_exercise_summary.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example 2: Bug Fix Task
|
||||
|
||||
**User Request:** "Fix the login bug in the authentication module"
|
||||
|
||||
### task_plan.md
|
||||
```markdown
|
||||
# Task Plan: Fix Login Bug
|
||||
|
||||
## Goal
|
||||
Identify and fix the bug preventing successful login.
|
||||
|
||||
## Phases
|
||||
- [x] Phase 1: Understand the bug report ✓
|
||||
- [x] Phase 2: Locate relevant code ✓
|
||||
- [ ] Phase 3: Identify root cause (CURRENT)
|
||||
- [ ] Phase 4: Implement fix
|
||||
- [ ] Phase 5: Test and verify
|
||||
|
||||
## Key Questions
|
||||
1. What error message appears?
|
||||
2. Which file handles authentication?
|
||||
3. What changed recently?
|
||||
|
||||
## Decisions Made
|
||||
- Auth handler is in src/auth/login.ts
|
||||
- Error occurs in validateToken() function
|
||||
|
||||
## Errors Encountered
|
||||
- [Initial] TypeError: Cannot read property 'token' of undefined
|
||||
→ Root cause: user object not awaited properly
|
||||
|
||||
## Status
|
||||
**Currently in Phase 3** - Found root cause, preparing fix
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example 3: Feature Development
|
||||
|
||||
**User Request:** "Add a dark mode toggle to the settings page"
|
||||
|
||||
### The 3-File Pattern in Action
|
||||
|
||||
**task_plan.md:**
|
||||
```markdown
|
||||
# Task Plan: Dark Mode Toggle
|
||||
|
||||
## Goal
|
||||
Add functional dark mode toggle to settings.
|
||||
|
||||
## Phases
|
||||
- [x] Phase 1: Research existing theme system ✓
|
||||
- [x] Phase 2: Design implementation approach ✓
|
||||
- [ ] Phase 3: Implement toggle component (CURRENT)
|
||||
- [ ] Phase 4: Add theme switching logic
|
||||
- [ ] Phase 5: Test and polish
|
||||
|
||||
## Decisions Made
|
||||
- Using CSS custom properties for theme
|
||||
- Storing preference in localStorage
|
||||
- Toggle component in SettingsPage.tsx
|
||||
|
||||
## Status
|
||||
**Currently in Phase 3** - Building toggle component
|
||||
```
|
||||
|
||||
**notes.md:**
|
||||
```markdown
|
||||
# Notes: Dark Mode Implementation
|
||||
|
||||
## Existing Theme System
|
||||
- Located in: src/styles/theme.ts
|
||||
- Uses: CSS custom properties
|
||||
- Current themes: light only
|
||||
|
||||
## Files to Modify
|
||||
1. src/styles/theme.ts - Add dark theme colors
|
||||
2. src/components/SettingsPage.tsx - Add toggle
|
||||
3. src/hooks/useTheme.ts - Create new hook
|
||||
4. src/App.tsx - Wrap with ThemeProvider
|
||||
|
||||
## Color Decisions
|
||||
- Dark background: #1a1a2e
|
||||
- Dark surface: #16213e
|
||||
- Dark text: #eaeaea
|
||||
```
|
||||
|
||||
**dark_mode_implementation.md:** (deliverable)
|
||||
```markdown
|
||||
# Dark Mode Implementation
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Added dark theme colors
|
||||
File: src/styles/theme.ts
|
||||
...
|
||||
|
||||
### 2. Created useTheme hook
|
||||
File: src/hooks/useTheme.ts
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example 4: Error Recovery Pattern
|
||||
|
||||
When something fails, DON'T hide it:
|
||||
|
||||
### Before (Wrong)
|
||||
```
|
||||
Action: Read config.json
|
||||
Error: File not found
|
||||
Action: Read config.json # Silent retry
|
||||
Action: Read config.json # Another retry
|
||||
```
|
||||
|
||||
### After (Correct)
|
||||
```
|
||||
Action: Read config.json
|
||||
Error: File not found
|
||||
|
||||
# Update task_plan.md:
|
||||
## Errors Encountered
|
||||
- config.json not found → Will create default config
|
||||
|
||||
Action: Write config.json (default config)
|
||||
Action: Read config.json
|
||||
Success!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The Read-Before-Decide Pattern
|
||||
|
||||
**Always read your plan before major decisions:**
|
||||
|
||||
```
|
||||
[Many tool calls have happened...]
|
||||
[Context is getting long...]
|
||||
[Original goal might be forgotten...]
|
||||
|
||||
→ Read task_plan.md # This brings goals back into attention!
|
||||
→ Now make the decision # Goals are fresh in context
|
||||
```
|
||||
|
||||
This is why Manus can handle ~50 tool calls without losing track. The plan file acts as a "goal refresh" mechanism.
|
||||
@@ -0,0 +1,218 @@
|
||||
# Reference: Manus Context Engineering Principles
|
||||
|
||||
This skill is based on context engineering principles from Manus, the AI agent company acquired by Meta for $2 billion in December 2025.
|
||||
|
||||
## The 6 Manus Principles
|
||||
|
||||
### Principle 1: Design Around KV-Cache
|
||||
|
||||
> "KV-cache hit rate is THE single most important metric for production AI agents."
|
||||
|
||||
**Statistics:**
|
||||
- ~100:1 input-to-output token ratio
|
||||
- Cached tokens: $0.30/MTok vs Uncached: $3/MTok
|
||||
- 10x cost difference!
|
||||
|
||||
**Implementation:**
|
||||
- Keep prompt prefixes STABLE (single-token change invalidates cache)
|
||||
- NO timestamps in system prompts
|
||||
- Make context APPEND-ONLY with deterministic serialization
|
||||
|
||||
### Principle 2: Mask, Don't Remove
|
||||
|
||||
Don't dynamically remove tools (breaks KV-cache). Use logit masking instead.
|
||||
|
||||
**Best Practice:** Use consistent action prefixes (e.g., `browser_`, `shell_`, `file_`) for easier masking.
|
||||
|
||||
### Principle 3: Filesystem as External Memory
|
||||
|
||||
> "Markdown is my 'working memory' on disk."
|
||||
|
||||
**The Formula:**
|
||||
```
|
||||
Context Window = RAM (volatile, limited)
|
||||
Filesystem = Disk (persistent, unlimited)
|
||||
```
|
||||
|
||||
**Compression Must Be Restorable:**
|
||||
- Keep URLs even if web content is dropped
|
||||
- Keep file paths when dropping document contents
|
||||
- Never lose the pointer to full data
|
||||
|
||||
### Principle 4: Manipulate Attention Through Recitation
|
||||
|
||||
> "Creates and updates todo.md throughout tasks to push global plan into model's recent attention span."
|
||||
|
||||
**Problem:** After ~50 tool calls, models forget original goals ("lost in the middle" effect).
|
||||
|
||||
**Solution:** Re-read `task_plan.md` before each decision. Goals appear in the attention window.
|
||||
|
||||
```
|
||||
Start of context: [Original goal - far away, forgotten]
|
||||
...many tool calls...
|
||||
End of context: [Recently read task_plan.md - gets ATTENTION!]
|
||||
```
|
||||
|
||||
### Principle 5: Keep the Wrong Stuff In
|
||||
|
||||
> "Leave the wrong turns in the context."
|
||||
|
||||
**Why:**
|
||||
- Failed actions with stack traces let model implicitly update beliefs
|
||||
- Reduces mistake repetition
|
||||
- Error recovery is "one of the clearest signals of TRUE agentic behavior"
|
||||
|
||||
### Principle 6: Don't Get Few-Shotted
|
||||
|
||||
> "Uniformity breeds fragility."
|
||||
|
||||
**Problem:** Repetitive action-observation pairs cause drift and hallucination.
|
||||
|
||||
**Solution:** Introduce controlled variation:
|
||||
- Vary phrasings slightly
|
||||
- Don't copy-paste patterns blindly
|
||||
- Recalibrate on repetitive tasks
|
||||
|
||||
---
|
||||
|
||||
## The 3 Context Engineering Strategies
|
||||
|
||||
Based on Lance Martin's analysis of Manus architecture.
|
||||
|
||||
### Strategy 1: Context Reduction
|
||||
|
||||
**Compaction:**
|
||||
```
|
||||
Tool calls have TWO representations:
|
||||
├── FULL: Raw tool content (stored in filesystem)
|
||||
└── COMPACT: Reference/file path only
|
||||
|
||||
RULES:
|
||||
- Apply compaction to STALE (older) tool results
|
||||
- Keep RECENT results FULL (to guide next decision)
|
||||
```
|
||||
|
||||
**Summarization:**
|
||||
- Applied when compaction reaches diminishing returns
|
||||
- Generated using full tool results
|
||||
- Creates standardized summary objects
|
||||
|
||||
### Strategy 2: Context Isolation (Multi-Agent)
|
||||
|
||||
**Architecture:**
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ PLANNER AGENT │
|
||||
│ └─ Assigns tasks to sub-agents │
|
||||
├─────────────────────────────────┤
|
||||
│ KNOWLEDGE MANAGER │
|
||||
│ └─ Reviews conversations │
|
||||
│ └─ Determines filesystem store │
|
||||
├─────────────────────────────────┤
|
||||
│ EXECUTOR SUB-AGENTS │
|
||||
│ └─ Perform assigned tasks │
|
||||
│ └─ Have own context windows │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Key Insight:** Manus originally used `todo.md` for task planning but found ~33% of actions were spent updating it. Shifted to dedicated planner agent calling executor sub-agents.
|
||||
|
||||
### Strategy 3: Context Offloading
|
||||
|
||||
**Tool Design:**
|
||||
- Use <20 atomic functions total
|
||||
- Store full results in filesystem, not context
|
||||
- Use `glob` and `grep` for searching
|
||||
- Progressive disclosure: load information only as needed
|
||||
|
||||
---
|
||||
|
||||
## The Agent Loop
|
||||
|
||||
Manus operates in a continuous 7-step loop:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 1. ANALYZE CONTEXT │
|
||||
│ - Understand user intent │
|
||||
│ - Assess current state │
|
||||
│ - Review recent observations │
|
||||
├─────────────────────────────────────────┤
|
||||
│ 2. THINK │
|
||||
│ - Should I update the plan? │
|
||||
│ - What's the next logical action? │
|
||||
│ - Are there blockers? │
|
||||
├─────────────────────────────────────────┤
|
||||
│ 3. SELECT TOOL │
|
||||
│ - Choose ONE tool │
|
||||
│ - Ensure parameters available │
|
||||
├─────────────────────────────────────────┤
|
||||
│ 4. EXECUTE ACTION │
|
||||
│ - Tool runs in sandbox │
|
||||
├─────────────────────────────────────────┤
|
||||
│ 5. RECEIVE OBSERVATION │
|
||||
│ - Result appended to context │
|
||||
├─────────────────────────────────────────┤
|
||||
│ 6. ITERATE │
|
||||
│ - Return to step 1 │
|
||||
│ - Continue until complete │
|
||||
├─────────────────────────────────────────┤
|
||||
│ 7. DELIVER OUTCOME │
|
||||
│ - Send results to user │
|
||||
│ - Attach all relevant files │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Types Manus Creates
|
||||
|
||||
| File | Purpose | When Created | When Updated |
|
||||
|------|---------|--------------|--------------|
|
||||
| `task_plan.md` | Phase tracking, progress | Task start | After completing phases |
|
||||
| `findings.md` | Discoveries, decisions | After ANY discovery | After viewing images/PDFs |
|
||||
| `progress.md` | Session log, what's done | At breakpoints | Throughout session |
|
||||
| Code files | Implementation | Before execution | After errors |
|
||||
|
||||
---
|
||||
|
||||
## Critical Constraints
|
||||
|
||||
- **Single-Action Execution:** ONE tool call per turn. No parallel execution.
|
||||
- **Plan is Required:** Agent must ALWAYS know: goal, current phase, remaining phases
|
||||
- **Files are Memory:** Context = volatile. Filesystem = persistent.
|
||||
- **Never Repeat Failures:** If action failed, next action MUST be different
|
||||
- **Communication is a Tool:** Message types: `info` (progress), `ask` (blocking), `result` (terminal)
|
||||
|
||||
---
|
||||
|
||||
## Manus Statistics
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Average tool calls per task | ~50 |
|
||||
| Input-to-output token ratio | 100:1 |
|
||||
| Acquisition price | $2 billion |
|
||||
| Time to $100M revenue | 8 months |
|
||||
| Framework refactors since launch | 5 times |
|
||||
|
||||
---
|
||||
|
||||
## Key Quotes
|
||||
|
||||
> "Context window = RAM (volatile, limited). Filesystem = Disk (persistent, unlimited). Anything important gets written to disk."
|
||||
|
||||
> "if action_failed: next_action != same_action. Track what you tried. Mutate the approach."
|
||||
|
||||
> "Error recovery is one of the clearest signals of TRUE agentic behavior."
|
||||
|
||||
> "KV-cache hit rate is the single most important metric for a production-stage AI agent."
|
||||
|
||||
> "Leave the wrong turns in the context."
|
||||
|
||||
---
|
||||
|
||||
## Source
|
||||
|
||||
Based on Manus's official context engineering documentation:
|
||||
https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus
|
||||
@@ -0,0 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,120 @@
|
||||
# Initialize planning files for a new session
|
||||
# Usage: .\init-session.ps1 [project-name]
|
||||
|
||||
param(
|
||||
[string]$ProjectName = "project"
|
||||
)
|
||||
|
||||
$DATE = Get-Date -Format "yyyy-MM-dd"
|
||||
|
||||
Write-Host "Initializing planning files for: $ProjectName"
|
||||
|
||||
# Create task_plan.md if it doesn't exist
|
||||
if (-not (Test-Path "task_plan.md")) {
|
||||
@"
|
||||
# Task Plan: [Brief Description]
|
||||
|
||||
## Goal
|
||||
[One sentence describing the end state]
|
||||
|
||||
## Current Phase
|
||||
Phase 1
|
||||
|
||||
## Phases
|
||||
|
||||
### Phase 1: Requirements & Discovery
|
||||
- [ ] Understand user intent
|
||||
- [ ] Identify constraints
|
||||
- [ ] Document in findings.md
|
||||
- **Status:** in_progress
|
||||
|
||||
### Phase 2: Planning & Structure
|
||||
- [ ] Define approach
|
||||
- [ ] Create project structure
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 3: Implementation
|
||||
- [ ] Execute the plan
|
||||
- [ ] Write to files before executing
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 4: Testing & Verification
|
||||
- [ ] Verify requirements met
|
||||
- [ ] Document test results
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 5: Delivery
|
||||
- [ ] Review outputs
|
||||
- [ ] Deliver to user
|
||||
- **Status:** pending
|
||||
|
||||
## Decisions Made
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
|
||||
## Errors Encountered
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
"@ | Out-File -FilePath "task_plan.md" -Encoding UTF8
|
||||
Write-Host "Created task_plan.md"
|
||||
} else {
|
||||
Write-Host "task_plan.md already exists, skipping"
|
||||
}
|
||||
|
||||
# Create findings.md if it doesn't exist
|
||||
if (-not (Test-Path "findings.md")) {
|
||||
@"
|
||||
# Findings & Decisions
|
||||
|
||||
## Requirements
|
||||
-
|
||||
|
||||
## Research Findings
|
||||
-
|
||||
|
||||
## Technical Decisions
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
|
||||
## Issues Encountered
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
|
||||
## Resources
|
||||
-
|
||||
"@ | Out-File -FilePath "findings.md" -Encoding UTF8
|
||||
Write-Host "Created findings.md"
|
||||
} else {
|
||||
Write-Host "findings.md already exists, skipping"
|
||||
}
|
||||
|
||||
# Create progress.md if it doesn't exist
|
||||
if (-not (Test-Path "progress.md")) {
|
||||
@"
|
||||
# Progress Log
|
||||
|
||||
## Session: $DATE
|
||||
|
||||
### Current Status
|
||||
- **Phase:** 1 - Requirements & Discovery
|
||||
- **Started:** $DATE
|
||||
|
||||
### Actions Taken
|
||||
-
|
||||
|
||||
### Test Results
|
||||
| Test | Expected | Actual | Status |
|
||||
|------|----------|--------|--------|
|
||||
|
||||
### Errors
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
"@ | Out-File -FilePath "progress.md" -Encoding UTF8
|
||||
Write-Host "Created progress.md"
|
||||
} else {
|
||||
Write-Host "progress.md already exists, skipping"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Planning files initialized!"
|
||||
Write-Host "Files: task_plan.md, findings.md, progress.md"
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/bin/bash
|
||||
# Initialize planning files for a new session
|
||||
# Usage: ./init-session.sh [project-name]
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_NAME="${1:-project}"
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
|
||||
echo "Initializing planning files for: $PROJECT_NAME"
|
||||
|
||||
# Create task_plan.md if it doesn't exist
|
||||
if [ ! -f "task_plan.md" ]; then
|
||||
cat > task_plan.md << 'EOF'
|
||||
# Task Plan: [Brief Description]
|
||||
|
||||
## Goal
|
||||
[One sentence describing the end state]
|
||||
|
||||
## Current Phase
|
||||
Phase 1
|
||||
|
||||
## Phases
|
||||
|
||||
### Phase 1: Requirements & Discovery
|
||||
- [ ] Understand user intent
|
||||
- [ ] Identify constraints
|
||||
- [ ] Document in findings.md
|
||||
- **Status:** in_progress
|
||||
|
||||
### Phase 2: Planning & Structure
|
||||
- [ ] Define approach
|
||||
- [ ] Create project structure
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 3: Implementation
|
||||
- [ ] Execute the plan
|
||||
- [ ] Write to files before executing
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 4: Testing & Verification
|
||||
- [ ] Verify requirements met
|
||||
- [ ] Document test results
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 5: Delivery
|
||||
- [ ] Review outputs
|
||||
- [ ] Deliver to user
|
||||
- **Status:** pending
|
||||
|
||||
## Decisions Made
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
|
||||
## Errors Encountered
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
EOF
|
||||
echo "Created task_plan.md"
|
||||
else
|
||||
echo "task_plan.md already exists, skipping"
|
||||
fi
|
||||
|
||||
# Create findings.md if it doesn't exist
|
||||
if [ ! -f "findings.md" ]; then
|
||||
cat > findings.md << 'EOF'
|
||||
# Findings & Decisions
|
||||
|
||||
## Requirements
|
||||
-
|
||||
|
||||
## Research Findings
|
||||
-
|
||||
|
||||
## Technical Decisions
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
|
||||
## Issues Encountered
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
|
||||
## Resources
|
||||
-
|
||||
EOF
|
||||
echo "Created findings.md"
|
||||
else
|
||||
echo "findings.md already exists, skipping"
|
||||
fi
|
||||
|
||||
# Create progress.md if it doesn't exist
|
||||
if [ ! -f "progress.md" ]; then
|
||||
cat > progress.md << EOF
|
||||
# Progress Log
|
||||
|
||||
## Session: $DATE
|
||||
|
||||
### Current Status
|
||||
- **Phase:** 1 - Requirements & Discovery
|
||||
- **Started:** $DATE
|
||||
|
||||
### Actions Taken
|
||||
-
|
||||
|
||||
### Test Results
|
||||
| Test | Expected | Actual | Status |
|
||||
|------|----------|--------|--------|
|
||||
|
||||
### Errors
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
EOF
|
||||
echo "Created progress.md"
|
||||
else
|
||||
echo "progress.md already exists, skipping"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Planning files initialized!"
|
||||
echo "Files: task_plan.md, findings.md, progress.md"
|
||||
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Session Catchup Script for planning-with-files
|
||||
|
||||
Analyzes the previous session to find unsynced context after the last
|
||||
planning file update. Designed to run on SessionStart.
|
||||
|
||||
Usage: python3 session-catchup.py [project-path]
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
from datetime import datetime
|
||||
|
||||
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
|
||||
|
||||
|
||||
def get_project_dir(project_path: str) -> Path:
|
||||
"""Convert project path to Claude's storage path format."""
|
||||
sanitized = project_path.replace('/', '-')
|
||||
if not sanitized.startswith('-'):
|
||||
sanitized = '-' + sanitized
|
||||
sanitized = sanitized.replace('_', '-')
|
||||
return Path.home() / '.claude' / 'projects' / sanitized
|
||||
|
||||
|
||||
def get_sessions_sorted(project_dir: Path) -> List[Path]:
|
||||
"""Get all session files sorted by modification time (newest first)."""
|
||||
sessions = list(project_dir.glob('*.jsonl'))
|
||||
main_sessions = [s for s in sessions if not s.name.startswith('agent-')]
|
||||
return sorted(main_sessions, key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
|
||||
|
||||
def parse_session_messages(session_file: Path) -> List[Dict]:
|
||||
"""Parse all messages from a session file, preserving order."""
|
||||
messages = []
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
try:
|
||||
data = json.loads(line)
|
||||
data['_line_num'] = line_num
|
||||
messages.append(data)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return messages
|
||||
|
||||
|
||||
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
|
||||
"""
|
||||
Find the last time a planning file was written/edited.
|
||||
Returns (line_number, filename) or (-1, None) if not found.
|
||||
"""
|
||||
last_update_line = -1
|
||||
last_update_file = None
|
||||
|
||||
for msg in messages:
|
||||
msg_type = msg.get('type')
|
||||
|
||||
if msg_type == 'assistant':
|
||||
content = msg.get('message', {}).get('content', [])
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
|
||||
if tool_name in ('Write', 'Edit'):
|
||||
file_path = tool_input.get('file_path', '')
|
||||
for pf in PLANNING_FILES:
|
||||
if file_path.endswith(pf):
|
||||
last_update_line = msg['_line_num']
|
||||
last_update_file = pf
|
||||
|
||||
return last_update_line, last_update_file
|
||||
|
||||
|
||||
def extract_messages_after(messages: List[Dict], after_line: int) -> List[Dict]:
|
||||
"""Extract conversation messages after a certain line number."""
|
||||
result = []
|
||||
for msg in messages:
|
||||
if msg['_line_num'] <= after_line:
|
||||
continue
|
||||
|
||||
msg_type = msg.get('type')
|
||||
is_meta = msg.get('isMeta', False)
|
||||
|
||||
if msg_type == 'user' and not is_meta:
|
||||
content = msg.get('message', {}).get('content', '')
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get('type') == 'text':
|
||||
content = item.get('text', '')
|
||||
break
|
||||
else:
|
||||
content = ''
|
||||
|
||||
if content and isinstance(content, str):
|
||||
if content.startswith(('<local-command', '<command-', '<task-notification')):
|
||||
continue
|
||||
if len(content) > 20:
|
||||
result.append({'role': 'user', 'content': content, 'line': msg['_line_num']})
|
||||
|
||||
elif msg_type == 'assistant':
|
||||
msg_content = msg.get('message', {}).get('content', '')
|
||||
text_content = ''
|
||||
tool_uses = []
|
||||
|
||||
if isinstance(msg_content, str):
|
||||
text_content = msg_content
|
||||
elif isinstance(msg_content, list):
|
||||
for item in msg_content:
|
||||
if item.get('type') == 'text':
|
||||
text_content = item.get('text', '')
|
||||
elif item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
if tool_name == 'Edit':
|
||||
tool_uses.append(f"Edit: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Write':
|
||||
tool_uses.append(f"Write: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Bash':
|
||||
cmd = tool_input.get('command', '')[:80]
|
||||
tool_uses.append(f"Bash: {cmd}")
|
||||
else:
|
||||
tool_uses.append(f"{tool_name}")
|
||||
|
||||
if text_content or tool_uses:
|
||||
result.append({
|
||||
'role': 'assistant',
|
||||
'content': text_content[:600] if text_content else '',
|
||||
'tools': tool_uses,
|
||||
'line': msg['_line_num']
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
project_path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
||||
project_dir = get_project_dir(project_path)
|
||||
|
||||
# Check if planning files exist (indicates active task)
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise.
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# No previous sessions, nothing to catch up on
|
||||
return
|
||||
|
||||
sessions = get_sessions_sorted(project_dir)
|
||||
if len(sessions) < 1:
|
||||
return
|
||||
|
||||
# Find a substantial previous session
|
||||
target_session = None
|
||||
for session in sessions:
|
||||
if session.stat().st_size > 5000:
|
||||
target_session = session
|
||||
break
|
||||
|
||||
if not target_session:
|
||||
return
|
||||
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
return
|
||||
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
if not messages_after:
|
||||
return
|
||||
|
||||
# Output catchup report
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
if msg['role'] == 'user':
|
||||
print(f"USER: {msg['content'][:300]}")
|
||||
else:
|
||||
if msg.get('content'):
|
||||
print(f"CLAUDE: {msg['content'][:300]}")
|
||||
if msg.get('tools'):
|
||||
print(f" Tools: {', '.join(msg['tools'][:4])}")
|
||||
|
||||
print("\n--- RECOMMENDED ---")
|
||||
print("1. Run: git diff --stat")
|
||||
print("2. Read: task_plan.md, progress.md, findings.md")
|
||||
print("3. Update planning files based on above context")
|
||||
print("4. Continue with task")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,95 @@
|
||||
# Findings & Decisions
|
||||
<!--
|
||||
WHAT: Your knowledge base for the task. Stores everything you discover and decide.
|
||||
WHY: Context windows are limited. This file is your "external memory" - persistent and unlimited.
|
||||
WHEN: Update after ANY discovery, especially after 2 view/browser/search operations (2-Action Rule).
|
||||
-->
|
||||
|
||||
## Requirements
|
||||
<!--
|
||||
WHAT: What the user asked for, broken down into specific requirements.
|
||||
WHY: Keeps requirements visible so you don't forget what you're building.
|
||||
WHEN: Fill this in during Phase 1 (Requirements & Discovery).
|
||||
EXAMPLE:
|
||||
- Command-line interface
|
||||
- Add tasks
|
||||
- List all tasks
|
||||
- Delete tasks
|
||||
- Python implementation
|
||||
-->
|
||||
<!-- Captured from user request -->
|
||||
-
|
||||
|
||||
## Research Findings
|
||||
<!--
|
||||
WHAT: Key discoveries from web searches, documentation reading, or exploration.
|
||||
WHY: Multimodal content (images, browser results) doesn't persist. Write it down immediately.
|
||||
WHEN: After EVERY 2 view/browser/search operations, update this section (2-Action Rule).
|
||||
EXAMPLE:
|
||||
- Python's argparse module supports subcommands for clean CLI design
|
||||
- JSON module handles file persistence easily
|
||||
- Standard pattern: python script.py <command> [args]
|
||||
-->
|
||||
<!-- Key discoveries during exploration -->
|
||||
-
|
||||
|
||||
## Technical Decisions
|
||||
<!--
|
||||
WHAT: Architecture and implementation choices you've made, with reasoning.
|
||||
WHY: You'll forget why you chose a technology or approach. This table preserves that knowledge.
|
||||
WHEN: Update whenever you make a significant technical choice.
|
||||
EXAMPLE:
|
||||
| Use JSON for storage | Simple, human-readable, built-in Python support |
|
||||
| argparse with subcommands | Clean CLI: python todo.py add "task" |
|
||||
-->
|
||||
<!-- Decisions made with rationale -->
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| | |
|
||||
|
||||
## Issues Encountered
|
||||
<!--
|
||||
WHAT: Problems you ran into and how you solved them.
|
||||
WHY: Similar to errors in task_plan.md, but focused on broader issues (not just code errors).
|
||||
WHEN: Document when you encounter blockers or unexpected challenges.
|
||||
EXAMPLE:
|
||||
| Empty file causes JSONDecodeError | Added explicit empty file check before json.load() |
|
||||
-->
|
||||
<!-- Errors and how they were resolved -->
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| | |
|
||||
|
||||
## Resources
|
||||
<!--
|
||||
WHAT: URLs, file paths, API references, documentation links you've found useful.
|
||||
WHY: Easy reference for later. Don't lose important links in context.
|
||||
WHEN: Add as you discover useful resources.
|
||||
EXAMPLE:
|
||||
- Python argparse docs: https://docs.python.org/3/library/argparse.html
|
||||
- Project structure: src/main.py, src/utils.py
|
||||
-->
|
||||
<!-- URLs, file paths, API references -->
|
||||
-
|
||||
|
||||
## Visual/Browser Findings
|
||||
<!--
|
||||
WHAT: Information you learned from viewing images, PDFs, or browser results.
|
||||
WHY: CRITICAL - Visual/multimodal content doesn't persist in context. Must be captured as text.
|
||||
WHEN: IMMEDIATELY after viewing images or browser results. Don't wait!
|
||||
EXAMPLE:
|
||||
- Screenshot shows login form has email and password fields
|
||||
- Browser shows API returns JSON with "status" and "data" keys
|
||||
-->
|
||||
<!-- CRITICAL: Update after every 2 view/browser operations -->
|
||||
<!-- Multimodal content must be captured as text immediately -->
|
||||
-
|
||||
|
||||
---
|
||||
<!--
|
||||
REMINDER: The 2-Action Rule
|
||||
After every 2 view/browser/search operations, you MUST update this file.
|
||||
This prevents visual information from being lost when context resets.
|
||||
-->
|
||||
*Update this file after every 2 view/browser/search operations*
|
||||
*This prevents visual information from being lost*
|
||||
@@ -0,0 +1,114 @@
|
||||
# Progress Log
|
||||
<!--
|
||||
WHAT: Your session log - a chronological record of what you did, when, and what happened.
|
||||
WHY: Answers "What have I done?" in the 5-Question Reboot Test. Helps you resume after breaks.
|
||||
WHEN: Update after completing each phase or encountering errors. More detailed than task_plan.md.
|
||||
-->
|
||||
|
||||
## Session: [DATE]
|
||||
<!--
|
||||
WHAT: The date of this work session.
|
||||
WHY: Helps track when work happened, useful for resuming after time gaps.
|
||||
EXAMPLE: 2026-01-15
|
||||
-->
|
||||
|
||||
### Phase 1: [Title]
|
||||
<!--
|
||||
WHAT: Detailed log of actions taken during this phase.
|
||||
WHY: Provides context for what was done, making it easier to resume or debug.
|
||||
WHEN: Update as you work through the phase, or at least when you complete it.
|
||||
-->
|
||||
- **Status:** in_progress
|
||||
- **Started:** [timestamp]
|
||||
<!--
|
||||
STATUS: Same as task_plan.md (pending, in_progress, complete)
|
||||
TIMESTAMP: When you started this phase (e.g., "2026-01-15 10:00")
|
||||
-->
|
||||
- Actions taken:
|
||||
<!--
|
||||
WHAT: List of specific actions you performed.
|
||||
EXAMPLE:
|
||||
- Created todo.py with basic structure
|
||||
- Implemented add functionality
|
||||
- Fixed FileNotFoundError
|
||||
-->
|
||||
-
|
||||
- Files created/modified:
|
||||
<!--
|
||||
WHAT: Which files you created or changed.
|
||||
WHY: Quick reference for what was touched. Helps with debugging and review.
|
||||
EXAMPLE:
|
||||
- todo.py (created)
|
||||
- todos.json (created by app)
|
||||
- task_plan.md (updated)
|
||||
-->
|
||||
-
|
||||
|
||||
### Phase 2: [Title]
|
||||
<!--
|
||||
WHAT: Same structure as Phase 1, for the next phase.
|
||||
WHY: Keep a separate log entry for each phase to track progress clearly.
|
||||
-->
|
||||
- **Status:** pending
|
||||
- Actions taken:
|
||||
-
|
||||
- Files created/modified:
|
||||
-
|
||||
|
||||
## Test Results
|
||||
<!--
|
||||
WHAT: Table of tests you ran, what you expected, what actually happened.
|
||||
WHY: Documents verification of functionality. Helps catch regressions.
|
||||
WHEN: Update as you test features, especially during Phase 4 (Testing & Verification).
|
||||
EXAMPLE:
|
||||
| Add task | python todo.py add "Buy milk" | Task added | Task added successfully | ✓ |
|
||||
| List tasks | python todo.py list | Shows all tasks | Shows all tasks | ✓ |
|
||||
-->
|
||||
| Test | Input | Expected | Actual | Status |
|
||||
|------|-------|----------|--------|--------|
|
||||
| | | | | |
|
||||
|
||||
## Error Log
|
||||
<!--
|
||||
WHAT: Detailed log of every error encountered, with timestamps and resolution attempts.
|
||||
WHY: More detailed than task_plan.md's error table. Helps you learn from mistakes.
|
||||
WHEN: Add immediately when an error occurs, even if you fix it quickly.
|
||||
EXAMPLE:
|
||||
| 2026-01-15 10:35 | FileNotFoundError | 1 | Added file existence check |
|
||||
| 2026-01-15 10:37 | JSONDecodeError | 2 | Added empty file handling |
|
||||
-->
|
||||
<!-- Keep ALL errors - they help avoid repetition -->
|
||||
| Timestamp | Error | Attempt | Resolution |
|
||||
|-----------|-------|---------|------------|
|
||||
| | | 1 | |
|
||||
|
||||
## 5-Question Reboot Check
|
||||
<!--
|
||||
WHAT: Five questions that verify your context is solid. If you can answer these, you're on track.
|
||||
WHY: This is the "reboot test" - if you can answer all 5, you can resume work effectively.
|
||||
WHEN: Update periodically, especially when resuming after a break or context reset.
|
||||
|
||||
THE 5 QUESTIONS:
|
||||
1. Where am I? → Current phase in task_plan.md
|
||||
2. Where am I going? → Remaining phases
|
||||
3. What's the goal? → Goal statement in task_plan.md
|
||||
4. What have I learned? → See findings.md
|
||||
5. What have I done? → See progress.md (this file)
|
||||
-->
|
||||
<!-- If you can answer these, context is solid -->
|
||||
| Question | Answer |
|
||||
|----------|--------|
|
||||
| Where am I? | Phase X |
|
||||
| Where am I going? | Remaining phases |
|
||||
| What's the goal? | [goal statement] |
|
||||
| What have I learned? | See findings.md |
|
||||
| What have I done? | See above |
|
||||
|
||||
---
|
||||
<!--
|
||||
REMINDER:
|
||||
- Update after completing each phase or encountering errors
|
||||
- Be detailed - this is your "what happened" log
|
||||
- Include timestamps for errors to track when issues occurred
|
||||
-->
|
||||
*Update after completing each phase or encountering errors*
|
||||
@@ -0,0 +1,132 @@
|
||||
# Task Plan: [Brief Description]
|
||||
<!--
|
||||
WHAT: This is your roadmap for the entire task. Think of it as your "working memory on disk."
|
||||
WHY: After 50+ tool calls, your original goals can get forgotten. This file keeps them fresh.
|
||||
WHEN: Create this FIRST, before starting any work. Update after each phase completes.
|
||||
-->
|
||||
|
||||
## Goal
|
||||
<!--
|
||||
WHAT: One clear sentence describing what you're trying to achieve.
|
||||
WHY: This is your north star. Re-reading this keeps you focused on the end state.
|
||||
EXAMPLE: "Create a Python CLI todo app with add, list, and delete functionality."
|
||||
-->
|
||||
[One sentence describing the end state]
|
||||
|
||||
## Current Phase
|
||||
<!--
|
||||
WHAT: Which phase you're currently working on (e.g., "Phase 1", "Phase 3").
|
||||
WHY: Quick reference for where you are in the task. Update this as you progress.
|
||||
-->
|
||||
Phase 1
|
||||
|
||||
## Phases
|
||||
<!--
|
||||
WHAT: Break your task into 3-7 logical phases. Each phase should be completable.
|
||||
WHY: Breaking work into phases prevents overwhelm and makes progress visible.
|
||||
WHEN: Update status after completing each phase: pending → in_progress → complete
|
||||
-->
|
||||
|
||||
### Phase 1: Requirements & Discovery
|
||||
<!--
|
||||
WHAT: Understand what needs to be done and gather initial information.
|
||||
WHY: Starting without understanding leads to wasted effort. This phase prevents that.
|
||||
-->
|
||||
- [ ] Understand user intent
|
||||
- [ ] Identify constraints and requirements
|
||||
- [ ] Document findings in findings.md
|
||||
- **Status:** in_progress
|
||||
<!--
|
||||
STATUS VALUES:
|
||||
- pending: Not started yet
|
||||
- in_progress: Currently working on this
|
||||
- complete: Finished this phase
|
||||
-->
|
||||
|
||||
### Phase 2: Planning & Structure
|
||||
<!--
|
||||
WHAT: Decide how you'll approach the problem and what structure you'll use.
|
||||
WHY: Good planning prevents rework. Document decisions so you remember why you chose them.
|
||||
-->
|
||||
- [ ] Define technical approach
|
||||
- [ ] Create project structure if needed
|
||||
- [ ] Document decisions with rationale
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 3: Implementation
|
||||
<!--
|
||||
WHAT: Actually build/create/write the solution.
|
||||
WHY: This is where the work happens. Break into smaller sub-tasks if needed.
|
||||
-->
|
||||
- [ ] Execute the plan step by step
|
||||
- [ ] Write code to files before executing
|
||||
- [ ] Test incrementally
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 4: Testing & Verification
|
||||
<!--
|
||||
WHAT: Verify everything works and meets requirements.
|
||||
WHY: Catching issues early saves time. Document test results in progress.md.
|
||||
-->
|
||||
- [ ] Verify all requirements met
|
||||
- [ ] Document test results in progress.md
|
||||
- [ ] Fix any issues found
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 5: Delivery
|
||||
<!--
|
||||
WHAT: Final review and handoff to user.
|
||||
WHY: Ensures nothing is forgotten and deliverables are complete.
|
||||
-->
|
||||
- [ ] Review all output files
|
||||
- [ ] Ensure deliverables are complete
|
||||
- [ ] Deliver to user
|
||||
- **Status:** pending
|
||||
|
||||
## Key Questions
|
||||
<!--
|
||||
WHAT: Important questions you need to answer during the task.
|
||||
WHY: These guide your research and decision-making. Answer them as you go.
|
||||
EXAMPLE:
|
||||
1. Should tasks persist between sessions? (Yes - need file storage)
|
||||
2. What format for storing tasks? (JSON file)
|
||||
-->
|
||||
1. [Question to answer]
|
||||
2. [Question to answer]
|
||||
|
||||
## Decisions Made
|
||||
<!--
|
||||
WHAT: Technical and design decisions you've made, with the reasoning behind them.
|
||||
WHY: You'll forget why you made choices. This table helps you remember and justify decisions.
|
||||
WHEN: Update whenever you make a significant choice (technology, approach, structure).
|
||||
EXAMPLE:
|
||||
| Use JSON for storage | Simple, human-readable, built-in Python support |
|
||||
-->
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| | |
|
||||
|
||||
## Errors Encountered
|
||||
<!--
|
||||
WHAT: Every error you encounter, what attempt number it was, and how you resolved it.
|
||||
WHY: Logging errors prevents repeating the same mistakes. This is critical for learning.
|
||||
WHEN: Add immediately when an error occurs, even if you fix it quickly.
|
||||
EXAMPLE:
|
||||
| FileNotFoundError | 1 | Check if file exists, create empty list if not |
|
||||
| JSONDecodeError | 2 | Handle empty file case explicitly |
|
||||
-->
|
||||
| Error | Attempt | Resolution |
|
||||
|-------|---------|------------|
|
||||
| | 1 | |
|
||||
|
||||
## Notes
|
||||
<!--
|
||||
REMINDERS:
|
||||
- Update phase status as you progress: pending → in_progress → complete
|
||||
- Re-read this plan before major decisions (attention manipulation)
|
||||
- Log ALL errors - they help avoid repetition
|
||||
- Never repeat a failed action - mutate your approach instead
|
||||
-->
|
||||
- Update phase status as you progress: pending → in_progress → complete
|
||||
- Re-read this plan before major decisions (attention manipulation)
|
||||
- Log ALL errors - they help avoid repetition
|
||||
@@ -1,17 +1,8 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.10.0"
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls. Now with automatic session recovery after /clear.
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
user-invocable: true
|
||||
allowed-tools:
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Bash
|
||||
- Glob
|
||||
- Grep
|
||||
- WebFetch
|
||||
- WebSearch
|
||||
allowed-tools: "Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch"
|
||||
hooks:
|
||||
PreToolUse:
|
||||
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
|
||||
@@ -27,7 +18,7 @@ hooks:
|
||||
- hooks:
|
||||
- type: command
|
||||
command: |
|
||||
SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/planning-with-files}/scripts"
|
||||
SCRIPT_DIR="${OPENCODE_SKILL_ROOT:-$HOME/.config/opencode/skills/planning-with-files}/scripts"
|
||||
|
||||
IS_WINDOWS=0
|
||||
if [ "${OS-}" = "Windows_NT" ]; then
|
||||
@@ -51,6 +42,8 @@ hooks:
|
||||
else
|
||||
sh "$SCRIPT_DIR/check-complete.sh"
|
||||
fi
|
||||
metadata:
|
||||
version: "2.16.1"
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
@@ -63,7 +56,7 @@ Work like Manus: Use persistent markdown files as your "working memory on disk."
|
||||
|
||||
```bash
|
||||
# Linux/macOS (auto-detects python3 or python)
|
||||
$(command -v python3 || command -v python) ${CLAUDE_PLUGIN_ROOT}/scripts/session-catchup.py "$(pwd)"
|
||||
$(command -v python3 || command -v python) ~/.config/opencode/skills/planning-with-files/scripts/session-catchup.py "$(pwd)"
|
||||
```
|
||||
|
||||
```powershell
|
||||
@@ -79,12 +72,12 @@ If catchup report shows unsynced context:
|
||||
|
||||
## Important: Where Files Go
|
||||
|
||||
- **Templates** are in `${CLAUDE_PLUGIN_ROOT}/templates/`
|
||||
- **Templates** are in `~/.config/opencode/skills/planning-with-files/templates/`
|
||||
- **Your planning files** go in **your project directory**
|
||||
|
||||
| Location | What Goes There |
|
||||
|----------|-----------------|
|
||||
| Skill directory (`${CLAUDE_PLUGIN_ROOT}/`) | Templates, scripts, reference docs |
|
||||
| Skill directory (`~/.config/opencode/skills/planning-with-files/`) | Templates, scripts, reference docs |
|
||||
| Your project directory | `task_plan.md`, `findings.md`, `progress.md` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,120 @@
|
||||
# Initialize planning files for a new session
|
||||
# Usage: .\init-session.ps1 [project-name]
|
||||
|
||||
param(
|
||||
[string]$ProjectName = "project"
|
||||
)
|
||||
|
||||
$DATE = Get-Date -Format "yyyy-MM-dd"
|
||||
|
||||
Write-Host "Initializing planning files for: $ProjectName"
|
||||
|
||||
# Create task_plan.md if it doesn't exist
|
||||
if (-not (Test-Path "task_plan.md")) {
|
||||
@"
|
||||
# Task Plan: [Brief Description]
|
||||
|
||||
## Goal
|
||||
[One sentence describing the end state]
|
||||
|
||||
## Current Phase
|
||||
Phase 1
|
||||
|
||||
## Phases
|
||||
|
||||
### Phase 1: Requirements & Discovery
|
||||
- [ ] Understand user intent
|
||||
- [ ] Identify constraints
|
||||
- [ ] Document in findings.md
|
||||
- **Status:** in_progress
|
||||
|
||||
### Phase 2: Planning & Structure
|
||||
- [ ] Define approach
|
||||
- [ ] Create project structure
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 3: Implementation
|
||||
- [ ] Execute the plan
|
||||
- [ ] Write to files before executing
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 4: Testing & Verification
|
||||
- [ ] Verify requirements met
|
||||
- [ ] Document test results
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 5: Delivery
|
||||
- [ ] Review outputs
|
||||
- [ ] Deliver to user
|
||||
- **Status:** pending
|
||||
|
||||
## Decisions Made
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
|
||||
## Errors Encountered
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
"@ | Out-File -FilePath "task_plan.md" -Encoding UTF8
|
||||
Write-Host "Created task_plan.md"
|
||||
} else {
|
||||
Write-Host "task_plan.md already exists, skipping"
|
||||
}
|
||||
|
||||
# Create findings.md if it doesn't exist
|
||||
if (-not (Test-Path "findings.md")) {
|
||||
@"
|
||||
# Findings & Decisions
|
||||
|
||||
## Requirements
|
||||
-
|
||||
|
||||
## Research Findings
|
||||
-
|
||||
|
||||
## Technical Decisions
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
|
||||
## Issues Encountered
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
|
||||
## Resources
|
||||
-
|
||||
"@ | Out-File -FilePath "findings.md" -Encoding UTF8
|
||||
Write-Host "Created findings.md"
|
||||
} else {
|
||||
Write-Host "findings.md already exists, skipping"
|
||||
}
|
||||
|
||||
# Create progress.md if it doesn't exist
|
||||
if (-not (Test-Path "progress.md")) {
|
||||
@"
|
||||
# Progress Log
|
||||
|
||||
## Session: $DATE
|
||||
|
||||
### Current Status
|
||||
- **Phase:** 1 - Requirements & Discovery
|
||||
- **Started:** $DATE
|
||||
|
||||
### Actions Taken
|
||||
-
|
||||
|
||||
### Test Results
|
||||
| Test | Expected | Actual | Status |
|
||||
|------|----------|--------|--------|
|
||||
|
||||
### Errors
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
"@ | Out-File -FilePath "progress.md" -Encoding UTF8
|
||||
Write-Host "Created progress.md"
|
||||
} else {
|
||||
Write-Host "progress.md already exists, skipping"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Planning files initialized!"
|
||||
Write-Host "Files: task_plan.md, findings.md, progress.md"
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/bin/bash
|
||||
# Initialize planning files for a new session
|
||||
# Usage: ./init-session.sh [project-name]
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_NAME="${1:-project}"
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
|
||||
echo "Initializing planning files for: $PROJECT_NAME"
|
||||
|
||||
# Create task_plan.md if it doesn't exist
|
||||
if [ ! -f "task_plan.md" ]; then
|
||||
cat > task_plan.md << 'EOF'
|
||||
# Task Plan: [Brief Description]
|
||||
|
||||
## Goal
|
||||
[One sentence describing the end state]
|
||||
|
||||
## Current Phase
|
||||
Phase 1
|
||||
|
||||
## Phases
|
||||
|
||||
### Phase 1: Requirements & Discovery
|
||||
- [ ] Understand user intent
|
||||
- [ ] Identify constraints
|
||||
- [ ] Document in findings.md
|
||||
- **Status:** in_progress
|
||||
|
||||
### Phase 2: Planning & Structure
|
||||
- [ ] Define approach
|
||||
- [ ] Create project structure
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 3: Implementation
|
||||
- [ ] Execute the plan
|
||||
- [ ] Write to files before executing
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 4: Testing & Verification
|
||||
- [ ] Verify requirements met
|
||||
- [ ] Document test results
|
||||
- **Status:** pending
|
||||
|
||||
### Phase 5: Delivery
|
||||
- [ ] Review outputs
|
||||
- [ ] Deliver to user
|
||||
- **Status:** pending
|
||||
|
||||
## Decisions Made
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
|
||||
## Errors Encountered
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
EOF
|
||||
echo "Created task_plan.md"
|
||||
else
|
||||
echo "task_plan.md already exists, skipping"
|
||||
fi
|
||||
|
||||
# Create findings.md if it doesn't exist
|
||||
if [ ! -f "findings.md" ]; then
|
||||
cat > findings.md << 'EOF'
|
||||
# Findings & Decisions
|
||||
|
||||
## Requirements
|
||||
-
|
||||
|
||||
## Research Findings
|
||||
-
|
||||
|
||||
## Technical Decisions
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
|
||||
## Issues Encountered
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
|
||||
## Resources
|
||||
-
|
||||
EOF
|
||||
echo "Created findings.md"
|
||||
else
|
||||
echo "findings.md already exists, skipping"
|
||||
fi
|
||||
|
||||
# Create progress.md if it doesn't exist
|
||||
if [ ! -f "progress.md" ]; then
|
||||
cat > progress.md << EOF
|
||||
# Progress Log
|
||||
|
||||
## Session: $DATE
|
||||
|
||||
### Current Status
|
||||
- **Phase:** 1 - Requirements & Discovery
|
||||
- **Started:** $DATE
|
||||
|
||||
### Actions Taken
|
||||
-
|
||||
|
||||
### Test Results
|
||||
| Test | Expected | Actual | Status |
|
||||
|------|----------|--------|--------|
|
||||
|
||||
### Errors
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
EOF
|
||||
echo "Created progress.md"
|
||||
else
|
||||
echo "progress.md already exists, skipping"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Planning files initialized!"
|
||||
echo "Files: task_plan.md, findings.md, progress.md"
|
||||
@@ -0,0 +1,269 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Session Catchup Script for planning-with-files
|
||||
|
||||
Analyzes the previous session to find unsynced context after the last
|
||||
planning file update. Designed to run on SessionStart.
|
||||
|
||||
Usage: python3 session-catchup.py [project-path]
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
|
||||
|
||||
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
|
||||
|
||||
|
||||
def get_project_dir(project_path: str) -> Path:
|
||||
"""Convert project path to OpenCode's storage path format."""
|
||||
# Normalize to an absolute path to ensure a stable representation
|
||||
# .as_posix() handles '\' -> '/' conversion on Windows automatically
|
||||
resolved_str = Path(project_path).resolve().as_posix()
|
||||
|
||||
# Sanitize path: replace separators with '-', remove ':' (Windows drives)
|
||||
sanitized = resolved_str.replace('/', '-').replace(':', '')
|
||||
|
||||
# Apply legacy naming convention: leading '-' and '_' -> '-'
|
||||
if not sanitized.startswith('-'):
|
||||
sanitized = '-' + sanitized
|
||||
sanitized_name = sanitized.replace('_', '-')
|
||||
|
||||
# 1. Check Legacy Location first (~/.opencode/sessions/...)
|
||||
legacy_dir = Path.home() / '.opencode' / 'sessions' / sanitized_name
|
||||
if legacy_dir.is_dir():
|
||||
return legacy_dir
|
||||
|
||||
# 2. Standard Layout
|
||||
data_root_env = os.getenv('OPENCODE_DATA_DIR')
|
||||
if data_root_env:
|
||||
data_root = Path(data_root_env)
|
||||
else:
|
||||
# Respect XDG_DATA_HOME if set, otherwise use default
|
||||
xdg_root = os.getenv('XDG_DATA_HOME')
|
||||
if xdg_root:
|
||||
data_root = Path(xdg_root) / 'opencode' / 'storage'
|
||||
else:
|
||||
data_root = Path.home() / '.local' / 'share' / 'opencode' / 'storage'
|
||||
|
||||
return data_root / 'session' / sanitized_name
|
||||
|
||||
|
||||
def get_sessions_sorted(project_dir: Path) -> List[Path]:
|
||||
"""Get all session files sorted by modification time (newest first)."""
|
||||
# Support both legacy JSONL (*.jsonl) and standard JSON (*.json) session files.
|
||||
sessions = list(project_dir.glob('*.jsonl')) + list(project_dir.glob('*.json'))
|
||||
# Deduplicate in case of overlaps and filter out agent-specific sessions.
|
||||
unique_sessions = {s for s in sessions}
|
||||
main_sessions = [s for s in unique_sessions if not s.name.startswith('agent-')]
|
||||
return sorted(main_sessions, key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
|
||||
|
||||
def parse_session_messages(session_file: Path) -> List[Dict]:
|
||||
"""Parse all messages from a session file, preserving order."""
|
||||
messages: List[Dict] = []
|
||||
|
||||
# First, try to parse the entire file as JSON (for *.json session files).
|
||||
try:
|
||||
with open(session_file, 'r') as f:
|
||||
content = f.read()
|
||||
if content.strip():
|
||||
data = json.loads(content)
|
||||
if isinstance(data, list):
|
||||
for idx, item in enumerate(data):
|
||||
if isinstance(item, dict):
|
||||
item['_line_num'] = idx
|
||||
messages.append(item)
|
||||
elif isinstance(data, dict):
|
||||
# Some formats may wrap messages in a top-level object.
|
||||
msg_list = data.get('messages')
|
||||
if isinstance(msg_list, list):
|
||||
for idx, item in enumerate(msg_list):
|
||||
if isinstance(item, dict):
|
||||
item['_line_num'] = idx
|
||||
messages.append(item)
|
||||
except json.JSONDecodeError:
|
||||
# Fall through to JSONL parsing if full-file JSON parsing fails.
|
||||
messages = []
|
||||
|
||||
if messages:
|
||||
return messages
|
||||
|
||||
# Fallback: treat file as JSONL (one JSON object per line), the original behavior.
|
||||
messages = []
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
try:
|
||||
data = json.loads(line)
|
||||
if isinstance(data, dict):
|
||||
data['_line_num'] = line_num
|
||||
messages.append(data)
|
||||
except json.JSONDecodeError:
|
||||
# Ignore malformed lines to be resilient to partial writes.
|
||||
# Some session log lines may be incomplete or non-JSON; skip them
|
||||
pass
|
||||
return messages
|
||||
|
||||
|
||||
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
|
||||
"""
|
||||
Find the last time a planning file was written/edited.
|
||||
Returns (line_number, filename) or (-1, None) if not found.
|
||||
"""
|
||||
last_update_line = -1
|
||||
last_update_file = None
|
||||
|
||||
for msg in messages:
|
||||
msg_type = msg.get('type')
|
||||
|
||||
if msg_type == 'assistant':
|
||||
content = msg.get('message', {}).get('content', [])
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
|
||||
if tool_name in ('Write', 'Edit'):
|
||||
file_path = tool_input.get('file_path', '')
|
||||
for pf in PLANNING_FILES:
|
||||
if file_path.endswith(pf):
|
||||
last_update_line = msg['_line_num']
|
||||
last_update_file = pf
|
||||
|
||||
return last_update_line, last_update_file
|
||||
|
||||
|
||||
def extract_messages_after(messages: List[Dict], after_line: int) -> List[Dict]:
|
||||
"""Extract conversation messages after a certain line number."""
|
||||
result = []
|
||||
for msg in messages:
|
||||
if msg['_line_num'] <= after_line:
|
||||
continue
|
||||
|
||||
msg_type = msg.get('type')
|
||||
is_meta = msg.get('isMeta', False)
|
||||
|
||||
if msg_type == 'user' and not is_meta:
|
||||
content = msg.get('message', {}).get('content', '')
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get('type') == 'text':
|
||||
content = item.get('text', '')
|
||||
break
|
||||
else:
|
||||
content = ''
|
||||
|
||||
if content and isinstance(content, str):
|
||||
if content.startswith(('<local-command', '<command-', '<task-notification')):
|
||||
continue
|
||||
if len(content) > 20:
|
||||
result.append({'role': 'user', 'content': content, 'line': msg['_line_num']})
|
||||
|
||||
elif msg_type == 'assistant':
|
||||
msg_content = msg.get('message', {}).get('content', '')
|
||||
text_content = ''
|
||||
tool_uses = []
|
||||
|
||||
if isinstance(msg_content, str):
|
||||
text_content = msg_content
|
||||
elif isinstance(msg_content, list):
|
||||
for item in msg_content:
|
||||
if item.get('type') == 'text':
|
||||
text_content = item.get('text', '')
|
||||
elif item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
if tool_name == 'Edit':
|
||||
tool_uses.append(f"Edit: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Write':
|
||||
tool_uses.append(f"Write: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Bash':
|
||||
cmd = tool_input.get('command', '')[:80]
|
||||
tool_uses.append(f"Bash: {cmd}")
|
||||
else:
|
||||
tool_uses.append(f"{tool_name}")
|
||||
|
||||
if text_content or tool_uses:
|
||||
result.append({
|
||||
'role': 'assistant',
|
||||
'content': text_content[:600] if text_content else '',
|
||||
'tools': tool_uses,
|
||||
'line': msg['_line_num']
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
project_path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
||||
project_dir = get_project_dir(project_path)
|
||||
|
||||
# Check if planning files exist (indicates active task)
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# No previous sessions, nothing to catch up on
|
||||
return
|
||||
|
||||
sessions = get_sessions_sorted(project_dir)
|
||||
if len(sessions) < 1:
|
||||
return
|
||||
|
||||
# Find a substantial previous session
|
||||
target_session = None
|
||||
for session in sessions:
|
||||
if session.stat().st_size > 5000:
|
||||
target_session = session
|
||||
break
|
||||
|
||||
if not target_session:
|
||||
return
|
||||
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
return
|
||||
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
if not messages_after:
|
||||
return
|
||||
|
||||
# Output catchup report
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
if msg['role'] == 'user':
|
||||
print(f"USER: {msg['content'][:300]}")
|
||||
else:
|
||||
if msg.get('content'):
|
||||
print(f"OPENCODE: {msg['content'][:300]}")
|
||||
if msg.get('tools'):
|
||||
print(f" Tools: {', '.join(msg['tools'][:4])}")
|
||||
|
||||
print("\n--- RECOMMENDED ---")
|
||||
print("1. Run: git diff --stat")
|
||||
print("2. Read: task_plan.md, progress.md, findings.md")
|
||||
print("3. Update planning files based on above context")
|
||||
print("4. Continue with task")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: pi-planning-with-files
|
||||
description: Implements Manus-style file-based planning for complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls
|
||||
description: Implements Manus-style file-based planning to organize and track progress on complex tasks. Creates task_plan.md, findings.md, and progress.md. Use when asked to plan out, break down, or organize a multi-step project, research task, or any work requiring >5 tool calls. Supports automatic session recovery after /clear.
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
param(
|
||||
[string]$PlanFile = "task_plan.md"
|
||||
)
|
||||
|
||||
if (-not (Test-Path $PlanFile)) {
|
||||
Write-Host "ERROR: $PlanFile not found"
|
||||
Write-Host "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
Write-Host "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "=== Task Completion Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# Read file content
|
||||
$content = Get-Content $PlanFile -Raw
|
||||
|
||||
# Count phases by status
|
||||
# Count total phases
|
||||
$TOTAL = ([regex]::Matches($content, "### Phase")).Count
|
||||
|
||||
# Check for **Status:** format first
|
||||
$COMPLETE = ([regex]::Matches($content, "\*\*Status:\*\* complete")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\*\*Status:\*\* in_progress")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\*\*Status:\*\* pending")).Count
|
||||
|
||||
Write-Host "Total phases: $TOTAL"
|
||||
Write-Host "Complete: $COMPLETE"
|
||||
Write-Host "In progress: $IN_PROGRESS"
|
||||
Write-Host "Pending: $PENDING"
|
||||
Write-Host ""
|
||||
|
||||
# Check completion
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "TASK NOT COMPLETE"
|
||||
Write-Host ""
|
||||
Write-Host "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if ($COMPLETE -eq 0 -and $IN_PROGRESS -eq 0 -and $PENDING -eq 0) {
|
||||
$COMPLETE = ([regex]::Matches($content, "\[complete\]")).Count
|
||||
$IN_PROGRESS = ([regex]::Matches($content, "\[in_progress\]")).Count
|
||||
$PENDING = ([regex]::Matches($content, "\[pending\]")).Count
|
||||
}
|
||||
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if ($COMPLETE -eq $TOTAL -and $TOTAL -gt 0) {
|
||||
Write-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
} else {
|
||||
Write-Host "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if ($IN_PROGRESS -gt 0) {
|
||||
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
}
|
||||
if ($PENDING -gt 0) {
|
||||
Write-Host "[planning-with-files] $PENDING phase(s) pending."
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Check if all phases in task_plan.md are complete
|
||||
# Exit 0 if complete, exit 1 if incomplete
|
||||
# Used by Stop hook to verify task completion
|
||||
# Always exits 0 — uses stdout for status reporting
|
||||
# Used by Stop hook to report task completion status
|
||||
|
||||
PLAN_FILE="${1:-task_plan.md}"
|
||||
|
||||
if [ ! -f "$PLAN_FILE" ]; then
|
||||
echo "ERROR: $PLAN_FILE not found"
|
||||
echo "Cannot verify completion without a task plan."
|
||||
exit 1
|
||||
echo "[planning-with-files] No task_plan.md found — no active planning session."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== Task Completion Check ==="
|
||||
echo ""
|
||||
|
||||
# Count phases by status (using -F for fixed string matching)
|
||||
# Count total phases
|
||||
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
||||
|
||||
# Check for **Status:** format first
|
||||
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
||||
|
||||
# Fallback: check for [complete] inline format if **Status:** not found
|
||||
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
|
||||
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" || true)
|
||||
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" || true)
|
||||
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" || true)
|
||||
fi
|
||||
|
||||
# Default to 0 if empty
|
||||
: "${TOTAL:=0}"
|
||||
: "${COMPLETE:=0}"
|
||||
: "${IN_PROGRESS:=0}"
|
||||
: "${PENDING:=0}"
|
||||
|
||||
echo "Total phases: $TOTAL"
|
||||
echo "Complete: $COMPLETE"
|
||||
echo "In progress: $IN_PROGRESS"
|
||||
echo "Pending: $PENDING"
|
||||
echo ""
|
||||
|
||||
# Check completion
|
||||
# Report status (always exit 0 — incomplete task is a normal state)
|
||||
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
||||
echo "ALL PHASES COMPLETE"
|
||||
exit 0
|
||||
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)"
|
||||
else
|
||||
echo "TASK NOT COMPLETE"
|
||||
echo ""
|
||||
echo "Do not stop until all phases are complete."
|
||||
exit 1
|
||||
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete)"
|
||||
if [ "$IN_PROGRESS" -gt 0 ]; then
|
||||
echo "[planning-with-files] $IN_PROGRESS phase(s) still in progress."
|
||||
fi
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
echo "[planning-with-files] $PENDING phase(s) pending."
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Session Catchup Script for planning-with-files (Pi Edition)
|
||||
Session Catchup Script for planning-with-files
|
||||
|
||||
Session-agnostic scanning: finds the most recent planning file update across
|
||||
ALL sessions, then collects all conversation from that point forward through
|
||||
all subsequent sessions until now.
|
||||
Analyzes the previous session to find unsynced context after the last
|
||||
planning file update. Designed to run on SessionStart.
|
||||
|
||||
Usage: python3 session-catchup.py [project-path]
|
||||
"""
|
||||
@@ -14,176 +13,127 @@ import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
from datetime import datetime
|
||||
|
||||
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
|
||||
|
||||
|
||||
def get_project_dir(project_path: str) -> Path:
|
||||
"""Convert project path to Pi's session storage path format."""
|
||||
# expanduser handles ~, abspath handles relative paths
|
||||
abs_path = os.path.abspath(os.path.expanduser(project_path))
|
||||
|
||||
# Pi treats paths as directory paths ending in /
|
||||
if not abs_path.endswith('/'):
|
||||
abs_path += '/'
|
||||
|
||||
# Pi session directory encoding:
|
||||
# 1. Replace '/' with '-'
|
||||
# 2. Wrap with '-' at start and end
|
||||
# e.g. /Users/tmr/ -> -Users-tmr- -> --Users-tmr--
|
||||
sanitized = abs_path.replace('/', '-')
|
||||
sanitized = '-' + sanitized + '-'
|
||||
|
||||
# Pi session storage is in ~/.pi/agent/sessions/
|
||||
return Path.home() / '.pi' / 'agent' / 'sessions' / sanitized
|
||||
"""Convert project path to Claude's storage path format."""
|
||||
sanitized = project_path.replace('/', '-')
|
||||
if not sanitized.startswith('-'):
|
||||
sanitized = '-' + sanitized
|
||||
sanitized = sanitized.replace('_', '-')
|
||||
return Path.home() / '.claude' / 'projects' / sanitized
|
||||
|
||||
|
||||
def get_sessions_sorted(project_dir: Path) -> List[Path]:
|
||||
"""Get all session files sorted by modification time (newest first)."""
|
||||
if not project_dir.exists():
|
||||
# Fallback: try without trailing slash doubling?
|
||||
# No, let's stick to the observed pattern.
|
||||
return []
|
||||
|
||||
sessions = list(project_dir.glob('*.jsonl'))
|
||||
# Filter out any non-session files if any
|
||||
sessions = [s for s in sessions if s.stat().st_size > 0]
|
||||
return sorted(sessions, key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
main_sessions = [s for s in sessions if not s.name.startswith('agent-')]
|
||||
return sorted(main_sessions, key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
|
||||
|
||||
def scan_for_planning_update(session_file: Path) -> Tuple[int, Optional[str]]:
|
||||
def parse_session_messages(session_file: Path) -> List[Dict]:
|
||||
"""Parse all messages from a session file, preserving order."""
|
||||
messages = []
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
try:
|
||||
data = json.loads(line)
|
||||
data['_line_num'] = line_num
|
||||
messages.append(data)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return messages
|
||||
|
||||
|
||||
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
|
||||
"""
|
||||
Quickly scan a session file for planning file updates.
|
||||
Returns (line_number, filename) of last update, or (-1, None) if none found.
|
||||
Find the last time a planning file was written/edited.
|
||||
Returns (line_number, filename) or (-1, None) if not found.
|
||||
"""
|
||||
last_update_line = -1
|
||||
last_update_file = None
|
||||
|
||||
try:
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
# Quick pre-filter
|
||||
line_lower = line.lower()
|
||||
if '"write"' not in line_lower and '"edit"' not in line_lower:
|
||||
continue
|
||||
for msg in messages:
|
||||
msg_type = msg.get('type')
|
||||
|
||||
try:
|
||||
entry = json.loads(line)
|
||||
if entry.get('type') != 'message':
|
||||
continue
|
||||
|
||||
message = entry.get('message', {})
|
||||
if message.get('role') != 'assistant':
|
||||
continue
|
||||
if msg_type == 'assistant':
|
||||
content = msg.get('message', {}).get('content', [])
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
|
||||
content = message.get('content', [])
|
||||
if not isinstance(content, list):
|
||||
continue
|
||||
|
||||
for item in content:
|
||||
if item.get('type') != 'toolCall':
|
||||
continue
|
||||
|
||||
tool_name = item.get('name', '').lower()
|
||||
if tool_name not in ('write', 'edit'):
|
||||
continue
|
||||
|
||||
args = item.get('arguments', {})
|
||||
# Pi tools usually use 'path'
|
||||
file_path = args.get('path', args.get('file_path', ''))
|
||||
|
||||
for pf in PLANNING_FILES:
|
||||
if file_path.endswith(pf):
|
||||
last_update_line = line_num
|
||||
last_update_file = pf
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
if tool_name in ('Write', 'Edit'):
|
||||
file_path = tool_input.get('file_path', '')
|
||||
for pf in PLANNING_FILES:
|
||||
if file_path.endswith(pf):
|
||||
last_update_line = msg['_line_num']
|
||||
last_update_file = pf
|
||||
|
||||
return last_update_line, last_update_file
|
||||
|
||||
|
||||
def extract_messages_from_session(session_file: Path, after_line: int = -1) -> List[Dict]:
|
||||
"""
|
||||
Extract conversation messages from a session file.
|
||||
If after_line >= 0, only extract messages after that line.
|
||||
If after_line < 0, extract all messages.
|
||||
"""
|
||||
def extract_messages_after(messages: List[Dict], after_line: int) -> List[Dict]:
|
||||
"""Extract conversation messages after a certain line number."""
|
||||
result = []
|
||||
|
||||
# Use short UUID for display
|
||||
session_id = session_file.stem.split('_')[-1][:8]
|
||||
for msg in messages:
|
||||
if msg['_line_num'] <= after_line:
|
||||
continue
|
||||
|
||||
try:
|
||||
with open(session_file, 'r') as f:
|
||||
for line_num, line in enumerate(f):
|
||||
if after_line >= 0 and line_num <= after_line:
|
||||
msg_type = msg.get('type')
|
||||
is_meta = msg.get('isMeta', False)
|
||||
|
||||
if msg_type == 'user' and not is_meta:
|
||||
content = msg.get('message', {}).get('content', '')
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get('type') == 'text':
|
||||
content = item.get('text', '')
|
||||
break
|
||||
else:
|
||||
content = ''
|
||||
|
||||
if content and isinstance(content, str):
|
||||
if content.startswith(('<local-command', '<command-', '<task-notification')):
|
||||
continue
|
||||
if len(content) > 20:
|
||||
result.append({'role': 'user', 'content': content, 'line': msg['_line_num']})
|
||||
|
||||
try:
|
||||
entry = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
elif msg_type == 'assistant':
|
||||
msg_content = msg.get('message', {}).get('content', '')
|
||||
text_content = ''
|
||||
tool_uses = []
|
||||
|
||||
if entry.get('type') != 'message':
|
||||
continue
|
||||
if isinstance(msg_content, str):
|
||||
text_content = msg_content
|
||||
elif isinstance(msg_content, list):
|
||||
for item in msg_content:
|
||||
if item.get('type') == 'text':
|
||||
text_content = item.get('text', '')
|
||||
elif item.get('type') == 'tool_use':
|
||||
tool_name = item.get('name', '')
|
||||
tool_input = item.get('input', {})
|
||||
if tool_name == 'Edit':
|
||||
tool_uses.append(f"Edit: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Write':
|
||||
tool_uses.append(f"Write: {tool_input.get('file_path', 'unknown')}")
|
||||
elif tool_name == 'Bash':
|
||||
cmd = tool_input.get('command', '')[:80]
|
||||
tool_uses.append(f"Bash: {cmd}")
|
||||
else:
|
||||
tool_uses.append(f"{tool_name}")
|
||||
|
||||
message = entry.get('message', {})
|
||||
role = message.get('role')
|
||||
content_list = message.get('content', [])
|
||||
|
||||
if role == 'user':
|
||||
text_content = ""
|
||||
for item in content_list:
|
||||
if item.get('type') == 'text':
|
||||
text_content += item.get('text', '')
|
||||
|
||||
if text_content:
|
||||
# Skip system/command messages if they look internal
|
||||
# But generally show user commands
|
||||
if len(text_content) > 0:
|
||||
result.append({
|
||||
'role': 'user',
|
||||
'content': text_content,
|
||||
'line': line_num,
|
||||
'session': session_id
|
||||
})
|
||||
|
||||
elif role == 'assistant':
|
||||
text_content = ''
|
||||
tool_uses = []
|
||||
|
||||
for item in content_list:
|
||||
if item.get('type') == 'text':
|
||||
text_content += item.get('text', '')
|
||||
elif item.get('type') == 'toolCall':
|
||||
tool_name = item.get('name', '')
|
||||
args = item.get('arguments', {})
|
||||
|
||||
if tool_name == 'edit':
|
||||
tool_uses.append(f"Edit: {args.get('path', 'unknown')}")
|
||||
elif tool_name == 'write':
|
||||
tool_uses.append(f"Write: {args.get('path', 'unknown')}")
|
||||
elif tool_name == 'bash':
|
||||
cmd = args.get('command', '')[:80]
|
||||
tool_uses.append(f"Bash: {cmd}")
|
||||
elif tool_name == 'read':
|
||||
tool_uses.append(f"Read: {args.get('path', 'unknown')}")
|
||||
else:
|
||||
tool_uses.append(f"{tool_name}")
|
||||
|
||||
if text_content or tool_uses:
|
||||
result.append({
|
||||
'role': 'assistant',
|
||||
'content': text_content[:600] if text_content else '',
|
||||
'tools': tool_uses,
|
||||
'line': line_num,
|
||||
'session': session_id
|
||||
})
|
||||
except Exception:
|
||||
pass
|
||||
if text_content or tool_uses:
|
||||
result.append({
|
||||
'role': 'assistant',
|
||||
'content': text_content[:600] if text_content else '',
|
||||
'tools': tool_uses,
|
||||
'line': msg['_line_num']
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
@@ -192,88 +142,59 @@ def main():
|
||||
project_path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
||||
project_dir = get_project_dir(project_path)
|
||||
|
||||
# Check if planning files exist (indicates active task)
|
||||
has_planning_files = any(
|
||||
Path(project_path, f).exists() for f in PLANNING_FILES
|
||||
)
|
||||
if not has_planning_files:
|
||||
# No planning files in this project; skip catchup to avoid noise.
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
# print(f"Session directory not found: {project_dir}")
|
||||
# No previous sessions, nothing to catch up on
|
||||
return
|
||||
|
||||
sessions = get_sessions_sorted(project_dir)
|
||||
if len(sessions) < 2:
|
||||
if len(sessions) < 1:
|
||||
return
|
||||
|
||||
# Skip the current session (most recently modified = index 0)
|
||||
previous_sessions = sessions[1:]
|
||||
|
||||
# Find the most recent planning file update across ALL previous sessions
|
||||
# Sessions are sorted newest first, so we scan in order
|
||||
update_session = None
|
||||
update_line = -1
|
||||
update_file = None
|
||||
update_session_idx = -1
|
||||
|
||||
for idx, session in enumerate(previous_sessions):
|
||||
line, filename = scan_for_planning_update(session)
|
||||
if line >= 0:
|
||||
update_session = session
|
||||
update_line = line
|
||||
update_file = filename
|
||||
update_session_idx = idx
|
||||
# Find a substantial previous session
|
||||
target_session = None
|
||||
for session in sessions:
|
||||
if session.stat().st_size > 5000:
|
||||
target_session = session
|
||||
break
|
||||
|
||||
if not update_session:
|
||||
# No planning file updates found in any previous session
|
||||
if not target_session:
|
||||
return
|
||||
|
||||
# Collect ALL messages from the update point forward, across all sessions
|
||||
all_messages = []
|
||||
messages = parse_session_messages(target_session)
|
||||
last_update_line, last_update_file = find_last_planning_update(messages)
|
||||
|
||||
# 1. Get messages from the session with the update (after the update line)
|
||||
messages_from_update_session = extract_messages_from_session(update_session, after_line=update_line)
|
||||
all_messages.extend(messages_from_update_session)
|
||||
# No planning updates in the target session; skip catchup output.
|
||||
if last_update_line < 0:
|
||||
return
|
||||
|
||||
# 2. Get ALL messages from sessions between update_session and current
|
||||
# These are sessions[1:update_session_idx] (newer than update_session)
|
||||
intermediate_sessions = previous_sessions[:update_session_idx]
|
||||
# Only output if there's unsynced content
|
||||
messages_after = extract_messages_after(messages, last_update_line)
|
||||
|
||||
# Process from oldest to newest for correct chronological order
|
||||
for session in reversed(intermediate_sessions):
|
||||
messages = extract_messages_from_session(session, after_line=-1) # Get all messages
|
||||
all_messages.extend(messages)
|
||||
|
||||
if not all_messages:
|
||||
if not messages_after:
|
||||
return
|
||||
|
||||
# Output catchup report
|
||||
print("\n[planning-with-files] SESSION CATCHUP DETECTED")
|
||||
print(f"Last planning update: {update_file} in session {update_session.stem.split('_')[-1][:8]}...")
|
||||
print(f"Previous session: {target_session.stem}")
|
||||
|
||||
sessions_covered = update_session_idx + 1
|
||||
if sessions_covered > 1:
|
||||
print(f"Scanning {sessions_covered} sessions for unsynced context")
|
||||
|
||||
print(f"Unsynced messages: {len(all_messages)}")
|
||||
print(f"Last planning update: {last_update_file} at message #{last_update_line}")
|
||||
print(f"Unsynced messages: {len(messages_after)}")
|
||||
|
||||
print("\n--- UNSYNCED CONTEXT ---")
|
||||
|
||||
# Show up to 100 messages
|
||||
MAX_MESSAGES = 100
|
||||
if len(all_messages) > MAX_MESSAGES:
|
||||
print(f"(Showing last {MAX_MESSAGES} of {len(all_messages)} messages)\n")
|
||||
messages_to_show = all_messages[-MAX_MESSAGES:]
|
||||
else:
|
||||
messages_to_show = all_messages
|
||||
|
||||
current_session = None
|
||||
for msg in messages_to_show:
|
||||
# Show session marker when it changes
|
||||
if msg.get('session') != current_session:
|
||||
current_session = msg.get('session')
|
||||
print(f"\n[Session: {current_session}...]")
|
||||
|
||||
for msg in messages_after[-15:]: # Last 15 messages
|
||||
if msg['role'] == 'user':
|
||||
print(f"USER: {msg['content'][:300]}")
|
||||
else:
|
||||
if msg.get('content'):
|
||||
print(f"PI: {msg['content'][:300]}")
|
||||
print(f"CLAUDE: {msg['content'][:300]}")
|
||||
if msg.get('tools'):
|
||||
print(f" Tools: {', '.join(msg['tools'][:4])}")
|
||||
|
||||
|
||||
+102
@@ -2,6 +2,108 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [2.18.2] - 2026-02-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Mastra Code hooks were silently doing nothing**
|
||||
- Root cause: Mastra Code reads hooks from `.mastracode/hooks.json`, not from SKILL.md frontmatter. The existing integration had hooks defined only in SKILL.md (Claude Code format), which Mastra Code ignores entirely. All three hooks (PreToolUse, PostToolUse, Stop) were non-functional.
|
||||
- Added `.mastracode/hooks.json` with proper Mastra Code format including `matcher`, `timeout`, and `description` fields
|
||||
- Fixed `MASTRACODE_SKILL_ROOT` env var in SKILL.md Stop hook (variable does not exist in Mastra Code, replaced with `$HOME` fallback to local path)
|
||||
- Bumped `.mastracode/skills/planning-with-files/SKILL.md` metadata version from 2.16.1 to 2.18.1
|
||||
- Corrected `docs/mastra.md` to accurately describe hooks.json (removed false claim that Mastra Code uses the same hook system as Claude Code)
|
||||
- Fixed personal installation instructions to include hooks.json copy step
|
||||
|
||||
---
|
||||
|
||||
## [2.18.1] - 2026-02-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Copilot hooks garbled characters — still broken after v2.16.1** (Issue #82, confirmed by @Hexiaopi)
|
||||
- Root cause: `Get-Content` in all PS1 scripts had no `-Encoding` parameter — PowerShell 5.x reads files using the system ANSI code page (Windows-1252) by default, corrupting any non-ASCII character in `task_plan.md` or `SKILL.md` before it reaches the output pipe. The v2.16.1 fix was correct but fixed only the output side, not the read side.
|
||||
- Secondary fix: `[System.Text.Encoding]::UTF8` returns UTF-8 with BOM — replaced with `[System.Text.UTF8Encoding]::new($false)` (UTF-8 without BOM) in all four PS1 scripts to prevent JSON parsers from receiving a stray `0xEF 0xBB 0xBF` preamble
|
||||
- Fixed files: `pre-tool-use.ps1`, `session-start.ps1`, `agent-stop.ps1`, `post-tool-use.ps1`
|
||||
- Bash scripts were already correct from v2.16.1
|
||||
|
||||
### Thanks
|
||||
|
||||
- @Hexiaopi for confirming the issue persisted after v2.16.1 (Issue #82)
|
||||
|
||||
---
|
||||
|
||||
## [2.18.0] - 2026-02-26
|
||||
|
||||
### Added
|
||||
|
||||
- **BoxLite sandbox runtime integration** (Issue #84 by @DorianZheng)
|
||||
- New `docs/boxlite.md` guide for running planning-with-files inside BoxLite micro-VM sandboxes via ClaudeBox
|
||||
- New `examples/boxlite/quickstart.py` — working Python example using ClaudeBox's Skill API to inject planning-with-files into a VM
|
||||
- New `examples/boxlite/README.md` — example context and requirements
|
||||
- README: new "Sandbox Runtimes" section (BoxLite is infrastructure, not an IDE — kept separate from the 16-platform IDE table)
|
||||
- README: BoxLite badge and Documentation table entry added
|
||||
- BoxLite loads via ClaudeBox (`pip install claudebox`) using its Python Skill object — no `.boxlite/` folder needed
|
||||
|
||||
### Thanks
|
||||
|
||||
- @DorianZheng for the BoxLite integration proposal (Issue #84)
|
||||
|
||||
---
|
||||
|
||||
## [2.17.0] - 2026-02-25
|
||||
|
||||
### Added
|
||||
|
||||
- **Mastra Code support** — new `.mastracode/skills/planning-with-files/` integration with native hooks (PreToolUse, PostToolUse, Stop), full scripts, templates, and installation guide (platform #16)
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Skill metadata spec compliance** — applied PR #83 fixes across all 12 IDE-specific SKILL.md files:
|
||||
- `allowed-tools` YAML list → comma-separated string (Codex, Cursor, Kilocode, CodeBuddy, OpenCode)
|
||||
- `version` moved from top-level to `metadata.version` across all applicable files
|
||||
- Description updated with trigger terms ("plan out", "break down", "organize", "track progress") in all IDEs
|
||||
- Version bumped to 2.16.1 everywhere, including canonical `skills/planning-with-files/SKILL.md`
|
||||
- OpenClaw inline JSON metadata expanded to proper block YAML
|
||||
|
||||
### Thanks
|
||||
|
||||
- @popey for the PR #83 spec fixes that identified the issues
|
||||
|
||||
---
|
||||
|
||||
## [2.16.1] - 2026-02-25
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Copilot hooks garbled characters on Windows** (Issue #82, reported by @Hexiaopi)
|
||||
- PowerShell scripts now set `$OutputEncoding` and `[Console]::OutputEncoding` to UTF-8 before any output — fixes garbled diamond characters (◆) caused by PowerShell 5.x defaulting to UTF-16LE stdout
|
||||
- Bash scripts now use `json.dumps(..., ensure_ascii=False)` — preserves UTF-8 characters (emojis, accented letters, CJK) in `task_plan.md` instead of converting them to raw `XXXX` escape sequences
|
||||
|
||||
### Thanks
|
||||
|
||||
- @Hexiaopi for reporting the garbled characters issue (Issue #82)
|
||||
|
||||
---
|
||||
|
||||
## [2.16.0] - 2026-02-22
|
||||
|
||||
### Added
|
||||
|
||||
- **GitHub Copilot Support** (PR #80 by @lincolnwan)
|
||||
- Native GitHub Copilot hooks integration (early 2026 hooks feature)
|
||||
- Created `.github/hooks/planning-with-files.json` configuration
|
||||
- Added full hook scripts in `.github/hooks/scripts/`
|
||||
- Cross-platform support (bash + PowerShell)
|
||||
- Added `docs/copilot.md` installation guide
|
||||
- Added GitHub Copilot badge to README
|
||||
- This brings total supported platforms to 15
|
||||
|
||||
### Thanks
|
||||
|
||||
- @lincolnwan for GitHub Copilot hooks support (PR #80)
|
||||
|
||||
---
|
||||
|
||||
## [2.14.0] - 2026-02-04
|
||||
|
||||
### Added
|
||||
|
||||
+9
-2
@@ -61,6 +61,12 @@ These amazing people have contributed code, documentation, or significant improv
|
||||
|
||||
### Other Contributors
|
||||
|
||||
- **[@gydx6](https://github.com/gydx6)** - [PR #79](https://github.com/OthmanAdi/planning-with-files/pull/79)
|
||||
- Fixed session-catchup false positives in all 9 skill-distributed copies
|
||||
- Added early return guards for non-planning projects
|
||||
- Thorough bug report with root cause analysis
|
||||
- **Impact:** Eliminates noise from false catchup reports
|
||||
|
||||
- **[@tobrun](https://github.com/tobrun)** - [PR #3](https://github.com/OthmanAdi/planning-with-files/pull/3)
|
||||
- Early directory structure improvements
|
||||
- Helped identify optimal repository layout
|
||||
@@ -86,6 +92,7 @@ These developers have created forks that extend the functionality:
|
||||
|
||||
Thank you to everyone who reported issues, provided feedback, and helped test fixes:
|
||||
|
||||
- [@DorianZheng](https://github.com/DorianZheng) - Issue #84 (BoxLite sandbox integration proposal)
|
||||
- [@mtuwei](https://github.com/mtuwei) - Issue #32 (Windows hook error)
|
||||
- [@JianweiWangs](https://github.com/JianweiWangs) - Issue #31 (Skill activation)
|
||||
- [@tingles2233](https://github.com/tingles2233) - Issue #29 (Plugin update issues)
|
||||
@@ -112,6 +119,6 @@ If you've contributed and don't see your name here, please open an issue! We wan
|
||||
|
||||
---
|
||||
|
||||
**Total Contributors:** 11+ and growing!
|
||||
**Total Contributors:** 13+ and growing!
|
||||
|
||||
*Last updated: January 27, 2026*
|
||||
*Last updated: February 26, 2026*
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
## Help Us Test Session Management Features!
|
||||
|
||||
I've implemented session management patterns from Anthropic's article ["Effective harnesses for long-running agents"](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents) in the **`feature/anthropic-patterns`** branch.
|
||||
|
||||
These features need testing before merging to main. **Your feedback is critical!**
|
||||
|
||||
---
|
||||
|
||||
## What's New
|
||||
|
||||
### 1. Session Initialization Script
|
||||
Run at the start of every session:
|
||||
```bash
|
||||
bash scripts/init-session.sh
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- ✅ Verifies planning files exist
|
||||
- ✅ Shows current phase and git status
|
||||
- ✅ Displays last commit
|
||||
- ✅ Logs session start to progress.md
|
||||
- ✅ Creates missing files if needed
|
||||
|
||||
### 2. Pass/Fail Status Tracking
|
||||
Enhanced `task_plan.md` template with:
|
||||
- Status icons: ⏸️ Pending | 🔄 In Progress | ✅ Pass | ❌ Fail | ⏭️ Skipped
|
||||
- Test Results table for each phase
|
||||
- Git Checkpoints table to log commits
|
||||
- Phase Summary table for quick overview
|
||||
|
||||
### 3. Git Checkpoint Workflow
|
||||
New documentation: `docs/git-checkpoints.md`
|
||||
- "One phase, one commit" pattern
|
||||
- Use git commits as rollback points
|
||||
- Integrates with task_plan.md
|
||||
|
||||
### 4. Session-Start Verification
|
||||
Automated checklist that verifies:
|
||||
- Planning files present
|
||||
- Git working tree clean
|
||||
- Current branch status
|
||||
- Last commit information
|
||||
|
||||
---
|
||||
|
||||
## How to Test
|
||||
|
||||
### 1. Checkout the Branch
|
||||
```bash
|
||||
cd your-planning-with-files-repo
|
||||
git fetch origin
|
||||
git checkout feature/anthropic-patterns
|
||||
```
|
||||
|
||||
### 2. Try It In a Test Project
|
||||
```bash
|
||||
cd ~/your-test-project
|
||||
bash /path/to/planning-with-files/scripts/init-session.sh
|
||||
```
|
||||
|
||||
### 3. Work Through a Multi-Phase Task
|
||||
- Let the script create planning files
|
||||
- Define some phases in task_plan.md
|
||||
- Complete a phase and test it
|
||||
- Mark it as ✅ Pass with test results
|
||||
- Commit: `git commit -m "feat(Phase 1): description"`
|
||||
- Log the commit hash in Git Checkpoints table
|
||||
- Start a new session and run init-session.sh again
|
||||
|
||||
### 4. Read the Implementation Summary
|
||||
See `IMPLEMENTATION_SUMMARY.md` in the branch for full details.
|
||||
|
||||
---
|
||||
|
||||
## What We Need Feedback On
|
||||
|
||||
1. **Does init-session.sh work on your system?**
|
||||
- Unix/Mac: Does the bash script run smoothly?
|
||||
- Windows: Does the PowerShell version work?
|
||||
|
||||
2. **Is the new task_plan.md template helpful?**
|
||||
- Are the status icons clear?
|
||||
- Is the Test Results table useful?
|
||||
- Does the Git Checkpoints table make sense?
|
||||
|
||||
3. **Does the workflow feel natural?**
|
||||
- Plan → Implement → Verify → Commit
|
||||
- Does session recovery work when you restart?
|
||||
|
||||
4. **Any bugs or issues?**
|
||||
- Errors when running scripts?
|
||||
- Confusing documentation?
|
||||
- Missing features?
|
||||
|
||||
5. **Suggestions for improvement?**
|
||||
- What would make this better?
|
||||
- Any patterns from the Anthropic article we missed?
|
||||
|
||||
---
|
||||
|
||||
## Related Issue
|
||||
|
||||
This work resolves [Issue #19](https://github.com/OthmanAdi/planning-with-files/issues/19) requested by @wqh17101.
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Git Checkpoint Workflow](https://github.com/OthmanAdi/planning-with-files/blob/feature/anthropic-patterns/docs/git-checkpoints.md)
|
||||
- [Implementation Summary](https://github.com/OthmanAdi/planning-with-files/blob/feature/anthropic-patterns/IMPLEMENTATION_SUMMARY.md)
|
||||
- [Anthropic Article](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents) (inspiration)
|
||||
|
||||
---
|
||||
|
||||
**Please test and share your experience!** Once we have enough feedback and approval, I'll merge this to main.
|
||||
|
||||
Thank you!
|
||||
|
||||
Ahmad
|
||||
@@ -2,12 +2,140 @@
|
||||
|
||||
> **Work like Manus** — the AI agent company Meta acquired for **$2 billion**.
|
||||
|
||||
## Thank You
|
||||
[](https://github.com/OthmanAdi/planning-with-files/issues?q=is%3Aissue+is%3Aclosed)
|
||||
[](https://github.com/OthmanAdi/planning-with-files/pulls?q=is%3Apr+is%3Aclosed)
|
||||
|
||||
<details>
|
||||
<summary><strong>💬 A Note from the Author</strong></summary>
|
||||
|
||||
To everyone who starred, forked, and shared this skill — thank you. This project blew up in less than 24 hours, and the support from the community has been incredible.
|
||||
|
||||
If this skill helps you work smarter, that's all I wanted.
|
||||
|
||||
</details>
|
||||
|
||||
<details open>
|
||||
<summary><strong>🌍 See What the Community Built</strong></summary>
|
||||
|
||||
| Fork | Author | Features |
|
||||
|------|--------|----------|
|
||||
| [devis](https://github.com/st01cs/devis) | [@st01cs](https://github.com/st01cs) | Interview-first workflow, `/devis:intv` and `/devis:impl` commands, guaranteed activation |
|
||||
| [multi-manus-planning](https://github.com/kmichels/multi-manus-planning) | [@kmichels](https://github.com/kmichels) | Multi-project support, SessionStart git sync |
|
||||
| [plan-cascade](https://github.com/Taoidle/plan-cascade) | [@Taoidle](https://github.com/Taoidle) | Multi-level task orchestration, parallel execution, multi-agent collaboration |
|
||||
| [agentfund-skill](https://github.com/RioTheGreat-ai/agentfund-skill) | [@RioTheGreat-ai](https://github.com/RioTheGreat-ai) | Crowdfunding for AI agents with milestone-based escrow on Base |
|
||||
|
||||
*Built something? [Open an issue](https://github.com/OthmanAdi/planning-with-files/issues) to get listed!*
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>🤝 Contributors</strong></summary>
|
||||
|
||||
Everyone who made this project better — bug reports, PRs, and integrations.
|
||||
|
||||
| Contributor | Contribution |
|
||||
|-------------|-------------|
|
||||
| [@popey](https://github.com/popey) | Skill metadata & discoverability fixes (PR #83) |
|
||||
| [@lincolnwan](https://github.com/lincolnwan) | GitHub Copilot hooks support (PR #80) |
|
||||
| [@gydx6](https://github.com/gydx6) | Session catchup false-positive fix (PR #79) |
|
||||
| [@ciberponk](https://github.com/ciberponk) | Isolated plan sessions with UUID pinning (PR #77) |
|
||||
| [@jonthebeef](https://github.com/jonthebeef) | `/plan:status` command (PR #75) |
|
||||
| [@codelyc](https://github.com/codelyc) | OpenCode scripts + CodeBuddy path fixes (PRs #76, #70, #66) |
|
||||
| [@ttttmr](https://github.com/ttttmr) | Pi Agent integration (PR #67) |
|
||||
| [@AZLabsAI](https://github.com/AZLabsAI) | OpenClaw docs update (PR #65) |
|
||||
| [@ZWkang](https://github.com/ZWkang) | CodeBuddy integration (PR #60) |
|
||||
| [@SaladDay](https://github.com/SaladDay) | POSIX stop hook fix (PR #57) |
|
||||
| [@murphyXu](https://github.com/murphyXu) | Continue IDE integration (PR #56) |
|
||||
| [@Guozihong](https://github.com/Guozihong) | Start command (PR #51) |
|
||||
| [@fahmyelraie](https://github.com/fahmyelraie) | Stop hook path resolution fix (PR #49) |
|
||||
| [@olgasafonova](https://github.com/olgasafonova) | SkillCheck validation badge (PR #46) |
|
||||
| [@lasmarois](https://github.com/lasmarois) | Session catchup cross-session improvements (PRs #37, #34) |
|
||||
| [@RioTheGreat-ai](https://github.com/RioTheGreat-ai) | AgentFund community extension (PR #72) |
|
||||
| [@Hexiaopi](https://github.com/Hexiaopi) | Copilot garbled characters bug report (Issue #82) |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>📦 Releases & Session Recovery</strong></summary>
|
||||
|
||||
### Current Version: v2.18.2
|
||||
|
||||
| Version | Highlights |
|
||||
|---------|------------|
|
||||
| **v2.18.2** | Mastra Code hooks fix (hooks.json + docs accuracy) |
|
||||
| **v2.18.1** | Copilot garbled characters complete fix |
|
||||
| **v2.18.0** | BoxLite sandbox runtime integration |
|
||||
| **v2.17.0** | Mastra Code support + all IDE SKILL.md spec fixes |
|
||||
| **v2.16.1** | Copilot garbled characters fix — PS1 UTF-8 encoding + bash ensure_ascii (thanks @Hexiaopi!) |
|
||||
| **v2.16.0** | GitHub Copilot hooks support (thanks @lincolnwan!) |
|
||||
| **v2.15.1** | Session catchup false-positive fix (thanks @gydx6!) |
|
||||
| **v2.15.0** | `/plan:status` command, OpenCode compatibility fix |
|
||||
| **v2.14.0** | Pi Agent support, OpenClaw docs update, Codex path fix |
|
||||
| **v2.11.0** | `/plan` command for easier autocomplete |
|
||||
| **v2.10.0** | Kiro steering files support |
|
||||
| **v2.7.0** | Gemini CLI support |
|
||||
| **v2.2.0** | Session recovery, Windows PowerShell, OS-aware hooks |
|
||||
|
||||
[View all releases](https://github.com/OthmanAdi/planning-with-files/releases) · [CHANGELOG](CHANGELOG.md)
|
||||
|
||||
> 🧪 **Experimental:** Isolated parallel planning (`.planning/{uuid}/` folders) is being tested on [`experimental/isolated-planning`](https://github.com/OthmanAdi/planning-with-files/tree/experimental/isolated-planning). Try it and share feedback!
|
||||
|
||||
---
|
||||
|
||||
### Session Recovery
|
||||
|
||||
When your context fills up and you run `/clear`, this skill **automatically recovers** your previous session.
|
||||
|
||||
**How it works:**
|
||||
1. Checks for previous session data in `~/.claude/projects/`
|
||||
2. Finds when planning files were last updated
|
||||
3. Extracts conversation that happened after (potentially lost context)
|
||||
4. Shows a catchup report so you can sync
|
||||
|
||||
**Pro tip:** Disable auto-compact to maximize context before clearing:
|
||||
```json
|
||||
{ "autoCompact": false }
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>🛠️ Supported IDEs (16 Platforms)</strong></summary>
|
||||
|
||||
| IDE | Status | Installation Guide | Format |
|
||||
|-----|--------|-------------------|--------|
|
||||
| Claude Code | ✅ Full Support | [Installation](docs/installation.md) | Plugin + SKILL.md |
|
||||
| Gemini CLI | ✅ Full Support | [Gemini Setup](docs/gemini.md) | Agent Skills |
|
||||
| OpenClaw | ✅ Full Support | [OpenClaw Setup](docs/openclaw.md) | Workspace/Local Skills |
|
||||
| Kiro | ✅ Full Support | [Kiro Setup](docs/kiro.md) | Steering Files |
|
||||
| Cursor | ✅ Full Support | [Cursor Setup](docs/cursor.md) | Skills + Hooks |
|
||||
| Continue | ✅ Full Support | [Continue Setup](docs/continue.md) | Skills + Prompt files |
|
||||
| Kilocode | ✅ Full Support | [Kilocode Setup](docs/kilocode.md) | Skills |
|
||||
| OpenCode | ✅ Full Support | [OpenCode Setup](docs/opencode.md) | Personal/Project Skill |
|
||||
| Codex | ✅ Full Support | [Codex Setup](docs/codex.md) | Personal Skill |
|
||||
| FactoryAI Droid | ✅ Full Support | [Factory Setup](docs/factory.md) | Workspace/Personal Skill |
|
||||
| Antigravity | ✅ Full Support | [Antigravity Setup](docs/antigravity.md) | Workspace/Personal Skill |
|
||||
| CodeBuddy | ✅ Full Support | [CodeBuddy Setup](docs/codebuddy.md) | Workspace/Personal Skill |
|
||||
| AdaL CLI (Sylph AI) | ✅ Full Support | [AdaL Setup](docs/adal.md) | Personal/Project Skills |
|
||||
| Pi Agent | ✅ Full Support | [Pi Agent Setup](docs/pi-agent.md) | Agent Skills |
|
||||
| GitHub Copilot | ✅ Full Support | [Copilot Setup](docs/copilot.md) | Hooks |
|
||||
| Mastra Code | ✅ Full Support | [Mastra Setup](docs/mastra.md) | Skills + Hooks |
|
||||
|
||||
> **Note:** If your IDE uses the legacy Rules system instead of Skills, see the [`legacy-rules-support`](https://github.com/OthmanAdi/planning-with-files/tree/legacy-rules-support) branch.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>🧱 Sandbox Runtimes (1 Platform)</strong></summary>
|
||||
|
||||
| Runtime | Status | Guide | Notes |
|
||||
|---------|--------|-------|-------|
|
||||
| BoxLite | ✅ Documented | [BoxLite Setup](docs/boxlite.md) | Run Claude Code + planning-with-files inside hardware-isolated micro-VMs |
|
||||
|
||||
> **Note:** BoxLite is a sandbox runtime, not an IDE. Skills load via [ClaudeBox](https://github.com/boxlite-ai/claudebox) — BoxLite’s official Claude Code integration layer.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
A Claude Code plugin that transforms your workflow to use persistent markdown files for planning, progress tracking, and knowledge storage — the exact pattern that made Manus worth billions.
|
||||
@@ -22,111 +150,43 @@ A Claude Code plugin that transforms your workflow to use persistent markdown fi
|
||||
[](https://kiro.dev/docs/cli/steering/)
|
||||
[](https://docs.sylph.ai/features/plugins-and-skills)
|
||||
[](https://pi.dev)
|
||||
[](https://github.com/OthmanAdi/planning-with-files/releases)
|
||||
[](https://docs.github.com/en/copilot/reference/hooks-configuration)
|
||||
[](https://code.mastra.ai)
|
||||
[](https://boxlite.ai)
|
||||
[](https://github.com/OthmanAdi/planning-with-files/releases)
|
||||
[](https://getskillcheck.com)
|
||||
|
||||
## Quick Install
|
||||
|
||||
```bash
|
||||
# Install the plugin
|
||||
claude plugins install OthmanAdi/planning-with-files
|
||||
In Claude Code, run:
|
||||
|
||||
```
|
||||
/plugin marketplace add OthmanAdi/planning-with-files
|
||||
/plugin install planning-with-files@planning-with-files
|
||||
```
|
||||
|
||||
That's it! Now use one of these commands in Claude Code:
|
||||
|
||||
| Command | Autocomplete | Description |
|
||||
|---------|--------------|-------------|
|
||||
| `/planning-with-files:plan` | Type `/plan` | Shorter command (v2.11.0+) |
|
||||
| `/planning-with-files:start` | Type `/planning` | Original command |
|
||||
| `/planning-with-files:plan` | Type `/plan` | Start planning session (v2.11.0+) |
|
||||
| `/planning-with-files:status` | Type `/plan:status` | Show planning progress at a glance (v2.15.0+) |
|
||||
| `/planning-with-files:start` | Type `/planning` | Original start command |
|
||||
|
||||
**Alternative:** If you want `/planning-with-files` (without prefix), copy skills to your local folder:
|
||||
|
||||
**macOS/Linux:**
|
||||
```bash
|
||||
# Optional: Copy skills for /planning-with-files command
|
||||
cp -r ~/.claude/plugins/cache/planning-with-files/planning-with-files/*/skills/planning-with-files ~/.claude/skills/
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
# Install the plugin
|
||||
claude plugins install OthmanAdi/planning-with-files
|
||||
|
||||
# Optional: Copy skills for /planning-with-files command
|
||||
Copy-Item -Recurse -Path "$env:USERPROFILE\.claude\plugins\cache\planning-with-files\planning-with-files\*\skills\planning-with-files" -Destination "$env:USERPROFILE\.claude\skills\"
|
||||
```
|
||||
|
||||
See [docs/installation.md](docs/installation.md) for all installation methods.
|
||||
|
||||
## Supported IDEs
|
||||
|
||||
| IDE | Status | Installation Guide | Format |
|
||||
|-----|--------|-------------------|--------|
|
||||
| Claude Code | ✅ Full Support | [Installation](docs/installation.md) | Plugin + SKILL.md |
|
||||
| Gemini CLI | ✅ Full Support | [Gemini Setup](docs/gemini.md) | Agent Skills |
|
||||
| OpenClaw | ✅ Full Support | [OpenClaw Setup](docs/openclaw.md) | Workspace/Local Skills |
|
||||
| Kiro | ✅ Full Support | [Kiro Setup](docs/kiro.md) | Steering Files |
|
||||
| Cursor | ✅ Full Support | [Cursor Setup](docs/cursor.md) | Skills |
|
||||
| Continue | ✅ Full Support | [Continue Setup](docs/continue.md) | Skills + Prompt files |
|
||||
| Kilocode | ✅ Full Support | [Kilocode Setup](docs/kilocode.md) | Skills |
|
||||
| OpenCode | ✅ Full Support | [OpenCode Setup](docs/opencode.md) | Personal/Project Skill |
|
||||
| Codex | ✅ Full Support | [Codex Setup](docs/codex.md) | Personal Skill |
|
||||
| FactoryAI Droid | ✅ Full Support | [Factory Setup](docs/factory.md) | Workspace/Personal Skill |
|
||||
| Antigravity | ✅ Full Support | [Antigravity Setup](docs/antigravity.md) | Workspace/Personal Skill |
|
||||
| CodeBuddy | ✅ Full Support | [CodeBuddy Setup](docs/codebuddy.md) | Workspace/Personal Skill |
|
||||
| AdaL CLI (Sylph AI) | ✅ Full Support | [AdaL Setup](docs/adal.md) | Personal/Project Skills |
|
||||
| Pi Agent | ✅ Full Support | [Pi Agent Setup](docs/pi-agent.md) | Agent Skills |
|
||||
|
||||
> **Note:** If your IDE uses the legacy Rules system instead of Skills, see the [`legacy-rules-support`](https://github.com/OthmanAdi/planning-with-files/tree/legacy-rules-support) branch.
|
||||
|
||||
## Documentation
|
||||
|
||||
| Document | Description |
|
||||
|----------|-------------|
|
||||
| [Installation Guide](docs/installation.md) | All installation methods (plugin, manual, Cursor, Windows) |
|
||||
| [Quick Start](docs/quickstart.md) | 5-step guide to using the pattern |
|
||||
| [Workflow Diagram](docs/workflow.md) | Visual diagram of how files and hooks interact |
|
||||
| [Troubleshooting](docs/troubleshooting.md) | Common issues and solutions |
|
||||
| [Gemini CLI Setup](docs/gemini.md) | Google Gemini CLI integration guide |
|
||||
| [OpenClaw Setup](docs/openclaw.md) | OpenClaw integration guide |
|
||||
| [Kiro Setup](docs/kiro.md) | Kiro steering files integration |
|
||||
| [Cursor Setup](docs/cursor.md) | Cursor IDE-specific instructions |
|
||||
| [Continue Setup](docs/continue.md) | Continue integration guide (skills + slash prompt) |
|
||||
| [Windows Setup](docs/windows.md) | Windows-specific notes |
|
||||
| [Kilo Code Support](docs/kilocode.md) | Kilo Code integration guide |
|
||||
| [Codex Setup](docs/codex.md) | Codex IDE installation and usage |
|
||||
| [OpenCode Setup](docs/opencode.md) | OpenCode IDE installation, oh-my-opencode config |
|
||||
| [FactoryAI Droid Setup](docs/factory.md) | FactoryAI Droid integration guide |
|
||||
| [Antigravity Setup](docs/antigravity.md) | Antigravity IDE integration guide |
|
||||
| [CodeBuddy Setup](docs/codebuddy.md) | CodeBuddy IDE integration guide |
|
||||
| [AdaL CLI Setup](docs/adal.md) | AdaL CLI / Sylph AI integration guide |
|
||||
| [Pi Agent Setup](docs/pi-agent.md) | Pi Agent integration guide |
|
||||
|
||||
## Versions
|
||||
|
||||
| Version | Features | Install |
|
||||
|---------|----------|---------|
|
||||
| **v2.14.0** (current) | Pi Agent support, OpenClaw docs update, Codex path fix | `claude plugins install OthmanAdi/planning-with-files` |
|
||||
| **v2.13.0** | Moltbot rebrand (formerly Clawd CLI) | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.12.0** | AdaL CLI / Sylph AI support | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.11.0** | `/plan` command for easier autocomplete | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.10.0** | Kiro steering files support | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.9.0** | Moltbot (formerly Clawd CLI) support | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.8.0** | Continue IDE support, POSIX sh compatibility fix | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.7.1** | Dynamic Python detection fix | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.7.0** | Gemini CLI support | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.6.0** | Start command (`/planning-with-files:start`), path resolution fix | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.5.0** | Fixed autocomplete - SKILL.md matches Anthropic format | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.3.0** | Codex & OpenCode IDE support | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.2.2** | Restored skill activation language | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.2.1** | Session recovery after /clear, enhanced PreToolUse hook | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.2.0** | Kilo Code IDE support, Windows PowerShell support, OS-aware hooks | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.1.2** | Fix template cache issue (Issue #18) | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.1.0** | Claude Code v2.1 compatible, PostToolUse hook, user-invocable | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.0.x** | Hooks, templates, scripts | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v1.0.0** (legacy) | Core 3-file pattern | `git clone -b legacy` |
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md) for details.
|
||||
|
||||
## Why This Skill?
|
||||
|
||||
On December 29, 2025, [Meta acquired Manus for $2 billion](https://techcrunch.com/2025/12/29/meta-just-bought-manus-an-ai-startup-everyone-has-been-talking-about/). In just 8 months, Manus went from launch to $100M+ revenue. Their secret? **Context engineering**.
|
||||
@@ -162,63 +222,35 @@ Filesystem = Disk (persistent, unlimited)
|
||||
→ Anything important gets written to disk.
|
||||
```
|
||||
|
||||
## The Manus Principles
|
||||
|
||||
| Principle | Implementation |
|
||||
|-----------|----------------|
|
||||
| Filesystem as memory | Store in files, not context |
|
||||
| Attention manipulation | Re-read plan before decisions (hooks) |
|
||||
| Error persistence | Log failures in plan file |
|
||||
| Goal tracking | Checkboxes show progress |
|
||||
| Completion verification | Stop hook checks all phases |
|
||||
|
||||
## Usage
|
||||
|
||||
Once installed, Claude will automatically:
|
||||
Once installed, the AI agent will:
|
||||
|
||||
1. **Create `task_plan.md`** before starting complex tasks
|
||||
2. **Re-read plan** before major decisions (via PreToolUse hook)
|
||||
3. **Remind you** to update status after file writes (via PostToolUse hook)
|
||||
4. **Store findings** in `findings.md` instead of stuffing context
|
||||
5. **Log errors** for future reference
|
||||
6. **Verify completion** before stopping (via Stop hook)
|
||||
1. **Ask for your task** if no description is provided
|
||||
2. **Create `task_plan.md`, `findings.md`, and `progress.md`** in your project directory
|
||||
3. **Re-read plan** before major decisions (via PreToolUse hook)
|
||||
4. **Remind you** to update status after file writes (via PostToolUse hook)
|
||||
5. **Store findings** in `findings.md` instead of stuffing context
|
||||
6. **Log errors** for future reference
|
||||
7. **Verify completion** before stopping (via Stop hook)
|
||||
|
||||
Or invoke manually:
|
||||
Invoke with:
|
||||
- `/planning-with-files:plan` - Type `/plan` to find in autocomplete (v2.11.0+)
|
||||
- `/planning-with-files:start` - Type `/planning` to find in autocomplete
|
||||
- `/planning-with-files` - Only if you copied skills to `~/.claude/skills/`
|
||||
|
||||
See [docs/quickstart.md](docs/quickstart.md) for the full 5-step guide.
|
||||
|
||||
## Session Recovery (NEW in v2.2.0)
|
||||
|
||||
When your context window fills up and you run `/clear`, this skill automatically recovers unsynced work from your previous session.
|
||||
|
||||
### Optimal Workflow
|
||||
|
||||
For the best experience, we recommend:
|
||||
|
||||
1. **Disable auto-compact** in Claude Code settings (use full context window)
|
||||
2. **Start a fresh session** in your project
|
||||
3. **Run `/planning-with-files`** when ready to work on a complex task
|
||||
4. **Work until context fills up** (Claude will warn you)
|
||||
5. **Run `/clear`** to start fresh
|
||||
6. **Run `/planning-with-files`** again — it will automatically recover where you left off
|
||||
|
||||
### How Recovery Works
|
||||
|
||||
When you invoke `/planning-with-files`, the skill:
|
||||
|
||||
1. Checks for previous session data (stored in `~/.claude/projects/`)
|
||||
2. Finds the last time planning files were updated
|
||||
3. Extracts conversation that happened after (potentially lost context)
|
||||
4. Shows a catchup report so you can sync planning files
|
||||
|
||||
This means even if context filled up before you could update your planning files, the skill will recover that context in your next session.
|
||||
|
||||
### Disabling Auto-Compact
|
||||
|
||||
To use the full context window without automatic compaction:
|
||||
|
||||
```bash
|
||||
# In your Claude Code settings or .claude/settings.json
|
||||
{
|
||||
"autoCompact": false
|
||||
}
|
||||
```
|
||||
|
||||
This lets you maximize context usage before manually clearing with `/clear`.
|
||||
|
||||
## Key Rules
|
||||
|
||||
1. **Create Plan First** — Never start without `task_plan.md`
|
||||
@@ -226,6 +258,19 @@ This lets you maximize context usage before manually clearing with `/clear`.
|
||||
3. **Log ALL Errors** — They help avoid repetition
|
||||
4. **Never Repeat Failures** — Track attempts, mutate approach
|
||||
|
||||
## When to Use
|
||||
|
||||
**Use this pattern for:**
|
||||
- Multi-step tasks (3+ steps)
|
||||
- Research tasks
|
||||
- Building/creating projects
|
||||
- Tasks spanning many tool calls
|
||||
|
||||
**Skip for:**
|
||||
- Simple questions
|
||||
- Single-file edits
|
||||
- Quick lookups
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
@@ -245,7 +290,13 @@ planning-with-files/
|
||||
│ ├── windows.md
|
||||
│ ├── kilocode.md
|
||||
│ ├── codex.md
|
||||
│ └── opencode.md
|
||||
│ ├── opencode.md
|
||||
│ ├── mastra.md # Mastra Code setup
|
||||
│ └── boxlite.md # BoxLite sandbox setup
|
||||
├── examples/ # Integration examples
|
||||
│ └── boxlite/ # BoxLite quickstart
|
||||
│ ├── README.md
|
||||
│ └── quickstart.py
|
||||
├── planning-with-files/ # Plugin skill folder
|
||||
│ ├── SKILL.md
|
||||
│ ├── templates/
|
||||
@@ -269,61 +320,56 @@ planning-with-files/
|
||||
├── .opencode/ # OpenCode IDE skills
|
||||
│ └── skills/
|
||||
├── .claude-plugin/ # Plugin manifest
|
||||
├── .cursor/ # Cursor skills
|
||||
├── .cursor/ # Cursor skills + hooks
|
||||
│ ├── hooks.json # Hook configuration
|
||||
│ ├── hooks/ # Hook scripts (bash + PowerShell)
|
||||
│ └── skills/
|
||||
├── .kilocode/ # Kilo Code skills
|
||||
│ └── skills/
|
||||
├── .openclaw/ # OpenClaw skills
|
||||
│ └── skills/
|
||||
├── .adal/ # AdaL CLI / Sylph AI skills
|
||||
│ └── skills/
|
||||
├── .pi/ # Pi Agent skills
|
||||
│ └── skills/
|
||||
│ └── planning-with-files/
|
||||
├── .github/ # GitHub Copilot hooks
|
||||
│ └── hooks/
|
||||
│ ├── planning-with-files.json # Hook configuration
|
||||
│ └── scripts/ # Hook scripts (bash + PowerShell)
|
||||
├── .mastracode/ # Mastra Code skills + hooks
|
||||
│ └── skills/
|
||||
├── CHANGELOG.md
|
||||
├── LICENSE
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## The Manus Principles
|
||||
## Documentation
|
||||
|
||||
| Principle | Implementation |
|
||||
|-----------|----------------|
|
||||
| Filesystem as memory | Store in files, not context |
|
||||
| Attention manipulation | Re-read plan before decisions (hooks) |
|
||||
| Error persistence | Log failures in plan file |
|
||||
| Goal tracking | Checkboxes show progress |
|
||||
| Completion verification | Stop hook checks all phases |
|
||||
| Document | Description |
|
||||
|----------|-------------|
|
||||
| [Installation Guide](docs/installation.md) | All installation methods (plugin, manual, Cursor, Windows) |
|
||||
| [Quick Start](docs/quickstart.md) | 5-step guide to using the pattern |
|
||||
| [Workflow Diagram](docs/workflow.md) | Visual diagram of how files and hooks interact |
|
||||
| [Troubleshooting](docs/troubleshooting.md) | Common issues and solutions |
|
||||
| [Gemini CLI Setup](docs/gemini.md) | Google Gemini CLI integration guide |
|
||||
| [OpenClaw Setup](docs/openclaw.md) | OpenClaw integration guide |
|
||||
| [Kiro Setup](docs/kiro.md) | Kiro steering files integration |
|
||||
| [Cursor Setup](docs/cursor.md) | Cursor IDE-specific instructions |
|
||||
| [Continue Setup](docs/continue.md) | Continue integration guide (skills + slash prompt) |
|
||||
| [Windows Setup](docs/windows.md) | Windows-specific notes |
|
||||
| [Kilo Code Support](docs/kilocode.md) | Kilo Code integration guide |
|
||||
| [Codex Setup](docs/codex.md) | Codex IDE installation and usage |
|
||||
| [OpenCode Setup](docs/opencode.md) | OpenCode IDE installation, oh-my-opencode config |
|
||||
| [FactoryAI Droid Setup](docs/factory.md) | FactoryAI Droid integration guide |
|
||||
| [Antigravity Setup](docs/antigravity.md) | Antigravity IDE integration guide |
|
||||
| [CodeBuddy Setup](docs/codebuddy.md) | CodeBuddy IDE integration guide |
|
||||
| [AdaL CLI Setup](docs/adal.md) | AdaL CLI / Sylph AI integration guide |
|
||||
| [Pi Agent Setup](docs/pi-agent.md) | Pi Agent integration guide |
|
||||
| [Copilot Setup](docs/copilot.md) | GitHub Copilot hooks integration guide |
|
||||
| [Mastra Setup](docs/mastra.md) | Mastra Code integration guide |
|
||||
| [BoxLite Setup](docs/boxlite.md) | BoxLite micro-VM sandbox integration guide |
|
||||
|
||||
## When to Use
|
||||
|
||||
**Use this pattern for:**
|
||||
- Multi-step tasks (3+ steps)
|
||||
- Research tasks
|
||||
- Building/creating projects
|
||||
- Tasks spanning many tool calls
|
||||
|
||||
**Skip for:**
|
||||
- Simple questions
|
||||
- Single-file edits
|
||||
- Quick lookups
|
||||
|
||||
## Kilo Code Support
|
||||
|
||||
This skill also supports Kilo Code AI through the `.kilocode/rules/` directory.
|
||||
|
||||
The [`.kilocode/rules/planning-with-files.md`](.kilocode/rules/planning-with-files.md) file contains all the planning guidelines formatted for Kilo Code's rules system, providing the same Manus-style planning workflow for Kilo Code users.
|
||||
|
||||
**Windows users:** The skill now includes PowerShell scripts ([`init-session.ps1`](skills/planning-with-files/scripts/init-session.ps1) and [`check-complete.ps1`](skills/planning-with-files/scripts/check-complete.ps1)) for native Windows support.
|
||||
|
||||
See [docs/kilocode.md](docs/kilocode.md) for detailed Kilo Code integration guide.
|
||||
|
||||
## Community Forks
|
||||
|
||||
| Fork | Author | Features |
|
||||
|------|--------|----------|
|
||||
| [devis](https://github.com/st01cs/devis) | [@st01cs](https://github.com/st01cs) | Interview-first workflow, `/devis:intv` and `/devis:impl` commands, guaranteed activation |
|
||||
| [multi-manus-planning](https://github.com/kmichels/multi-manus-planning) | [@kmichels](https://github.com/kmichels) | Multi-project support, SessionStart git sync |
|
||||
|
||||
*Built something? Open an issue to get listed!*
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
@@ -349,4 +395,4 @@ MIT License — feel free to use, modify, and distribute.
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#OthmanAdi/planning-with-files&Date)
|
||||
<a href="https://repostars.dev/?repos=OthmanAdi%2Fplanning-with-files&theme=copper"><img src="https://repostars.dev/api/embed?repo=OthmanAdi%2Fplanning-with-files&theme=copper" width="100%" alt="Star History Chart" /></a>
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
# Welcome to planning-with-files
|
||||
|
||||
> **Work like Manus** — the AI agent company Meta acquired for **$2 billion**.
|
||||
|
||||
This is a Claude Code skill that transforms your workflow to use persistent markdown files for planning, progress tracking, and knowledge storage.
|
||||
|
||||
## What This Project Does
|
||||
|
||||
Instead of relying on volatile context windows, planning-with-files teaches Claude to use **files as memory**:
|
||||
|
||||
- `task_plan.md` - Your roadmap (phases, progress, decisions)
|
||||
- `findings.md` - Research and discoveries
|
||||
- `progress.md` - Session logs and test results
|
||||
|
||||
When context fills up, you don't lose work. Everything important is on disk.
|
||||
|
||||
## Why It Exists
|
||||
|
||||
After 50+ tool calls, Claude forgets your original goals. This skill solves that by:
|
||||
- Re-reading the plan before major decisions (hooks)
|
||||
- Storing findings in files instead of context
|
||||
- Logging errors to prevent repetition
|
||||
- Verifying completion before stopping
|
||||
|
||||
## Inspired By
|
||||
|
||||
Manus AI pioneered this pattern and went from launch to $100M+ revenue in 8 months. Their secret? **Context engineering through persistent files.**
|
||||
|
||||
## Community ❤️
|
||||
|
||||
This project grew from **one developer's experiment** to **9,600+ stars** and **10+ contributors** in weeks.
|
||||
|
||||
**Thank you to everyone who:**
|
||||
- ⭐ Starred the repo
|
||||
- 🔀 Forked and built on this work
|
||||
- 🐛 Reported issues and tested fixes
|
||||
- 💡 Suggested features and improvements
|
||||
- 🛠️ Contributed code, docs, and examples
|
||||
|
||||
### Special Thanks
|
||||
|
||||
- **[@kaichen](https://github.com/kaichen)** - Converted to Claude Code plugin, made it accessible to thousands
|
||||
- **[@fuahyo](https://github.com/fuahyo)** - Created beginner-friendly walkthrough and examples
|
||||
- **[@lasmarois](https://github.com/lasmarois)** - Built session recovery feature, saved countless hours
|
||||
- **[@aimasteracc](https://github.com/aimasteracc)** - Added Windows support and Kilocode integration
|
||||
- **[@wqh17101](https://github.com/wqh17101)** - Inspired Anthropic patterns integration
|
||||
|
||||
And many more! See [CONTRIBUTORS.md](https://github.com/OthmanAdi/planning-with-files/blob/main/CONTRIBUTORS.md)
|
||||
|
||||
## Growing Together
|
||||
|
||||
What started as a simple 3-file pattern is now:
|
||||
- 5 IDE integrations (Claude Code, Cursor, Kilocode, OpenCode, Codex)
|
||||
- Session recovery after `/clear`
|
||||
- Git checkpoint workflows
|
||||
- Windows PowerShell support
|
||||
- Community forks and derivatives
|
||||
|
||||
**None of this would exist without you.**
|
||||
|
||||
## Get Involved
|
||||
|
||||
- 💬 [Discussions](https://github.com/OthmanAdi/planning-with-files/discussions) - Share your experience
|
||||
- 🐛 [Issues](https://github.com/OthmanAdi/planning-with-files/issues) - Report bugs or request features
|
||||
- 🔀 [Pull Requests](https://github.com/OthmanAdi/planning-with-files/pulls) - Contribute improvements
|
||||
- ⭐ Star if this helps you work smarter
|
||||
|
||||
## Quick Links
|
||||
|
||||
- [Installation Guide](https://github.com/OthmanAdi/planning-with-files/blob/main/docs/installation.md)
|
||||
- [Quick Start](https://github.com/OthmanAdi/planning-with-files/blob/main/docs/quickstart.md)
|
||||
- [Examples](https://github.com/OthmanAdi/planning-with-files/blob/main/examples/README.md)
|
||||
- [Changelog](https://github.com/OthmanAdi/planning-with-files/blob/main/CHANGELOG.md)
|
||||
|
||||
---
|
||||
|
||||
**Built with appreciation for the open source community.**
|
||||
|
||||
*Ahmad Othman Ammar Adi*
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
description: "Show current planning status at a glance - phases, progress, and any logged errors."
|
||||
---
|
||||
|
||||
Read task_plan.md from the current project directory and display a compact status summary.
|
||||
|
||||
## What to Show
|
||||
|
||||
1. **Current Phase**: Extract from "## Current Phase" section
|
||||
2. **Phase Progress**: Count phases and their status (pending/in_progress/complete)
|
||||
3. **Phase List**: Show each phase with status icon
|
||||
4. **Errors**: Count entries in "## Errors Encountered" table if present
|
||||
5. **Files Check**: Confirm which planning files exist
|
||||
|
||||
## Status Icons
|
||||
|
||||
- `[ ]` or "pending" → ⏸️
|
||||
- "in_progress" → 🔄
|
||||
- `[x]` or "complete" → ✅
|
||||
- "failed" or "blocked" → ❌
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
📋 Planning Status
|
||||
|
||||
Current: Phase {N} of {total} ({percent}%)
|
||||
Status: {status_icon} {status_text}
|
||||
|
||||
{icon} Phase 1: {name}
|
||||
{icon} Phase 2: {name} ← you are here
|
||||
{icon} Phase 3: {name}
|
||||
...
|
||||
|
||||
Files: task_plan.md {✓|✗} | findings.md {✓|✗} | progress.md {✓|✗}
|
||||
Errors logged: {count}
|
||||
```
|
||||
|
||||
## If No Planning Files Exist
|
||||
|
||||
```
|
||||
📋 No planning files found
|
||||
|
||||
Run /plan to start a new planning session.
|
||||
```
|
||||
|
||||
## Keep It Brief
|
||||
|
||||
This is a quick status check, not a full report. Show just enough to answer "where am I?" without re-reading all the files.
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
# BoxLite Setup
|
||||
|
||||
Using planning-with-files inside [BoxLite](https://boxlite.ai) micro-VM sandboxes via [ClaudeBox](https://github.com/boxlite-ai/claudebox).
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
BoxLite is a micro-VM sandbox runtime — hardware-isolated, stateful, embeddable as a library with no daemon and no root required. The analogy their team uses is "SQLite for sandboxing": you import it directly into your application and each box gets its own kernel, not just namespaces or containers.
|
||||
|
||||
[ClaudeBox](https://github.com/boxlite-ai/claudebox) is BoxLite's official Claude Code integration layer. It runs the Claude Code CLI inside a BoxLite micro-VM with persistent workspaces, optional skills, security policies, and resource limits. planning-with-files loads into ClaudeBox as a Skill object — the skill's SKILL.md and scripts get injected into the VM filesystem at startup, exactly where Claude Code expects to find them.
|
||||
|
||||
**Why use this combination:**
|
||||
- Run untrusted AI-generated code in hardware isolation without touching your host filesystem
|
||||
- planning files (`task_plan.md`, `findings.md`, `progress.md`) persist across sessions via ClaudeBox's stateful workspaces at `~/.claudebox/sessions/`
|
||||
- Snapshot before a risky phase, roll back if needed
|
||||
- All hooks (PreToolUse, PostToolUse, Stop) work because Claude Code runs natively inside the VM
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.10+
|
||||
- BoxLite runtime (installed automatically as a ClaudeBox dependency)
|
||||
- Docker — used to pull and manage OCI images (the sandbox itself runs as a micro-VM, not a Docker container)
|
||||
- `CLAUDE_CODE_OAUTH_TOKEN` or `ANTHROPIC_API_KEY` set
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Install ClaudeBox
|
||||
|
||||
```bash
|
||||
pip install claudebox
|
||||
```
|
||||
|
||||
### Set your API credentials
|
||||
|
||||
```bash
|
||||
export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...
|
||||
# or
|
||||
export ANTHROPIC_API_KEY=sk-ant-...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
The minimal example — planning-with-files inside a BoxLite VM:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
from claudebox import ClaudeBox, Skill
|
||||
|
||||
# Load the SKILL.md content from the installed skill
|
||||
SKILL_MD = Path.home() / ".claude" / "skills" / "planning-with-files" / "SKILL.md"
|
||||
|
||||
PLANNING_SKILL = Skill(
|
||||
name="planning-with-files",
|
||||
description="Manus-style file-based planning with persistent markdown",
|
||||
files={
|
||||
"/root/.claude/skills/planning-with-files/SKILL.md": SKILL_MD.read_text()
|
||||
}
|
||||
)
|
||||
|
||||
async def main():
|
||||
async with ClaudeBox(
|
||||
session_id="my-project",
|
||||
skills=[PLANNING_SKILL]
|
||||
) as box:
|
||||
result = await box.code(
|
||||
"Plan and implement a user authentication feature for the Express API"
|
||||
)
|
||||
print(result.response)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
Claude Code finds the skill at `/root/.claude/skills/planning-with-files/SKILL.md` inside the VM. The three planning files (`task_plan.md`, `findings.md`, `progress.md`) are written to the box's working directory and persist across sessions.
|
||||
|
||||
---
|
||||
|
||||
## Persistent Sessions
|
||||
|
||||
ClaudeBox workspaces survive restarts. Pick up exactly where you left off:
|
||||
|
||||
```python
|
||||
async def main():
|
||||
# First session — starts the plan
|
||||
async with ClaudeBox(session_id="auth-feature", skills=[PLANNING_SKILL]) as box:
|
||||
await box.code("Create task_plan.md for the authentication feature")
|
||||
|
||||
# Later session — same workspace, plan files still there
|
||||
async with ClaudeBox.reconnect("auth-feature") as box:
|
||||
await box.code("Continue implementing the login endpoint from the plan")
|
||||
|
||||
# Clean up when done
|
||||
await ClaudeBox.cleanup_session("auth-feature", remove_workspace=True)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How Hooks Work Inside the VM
|
||||
|
||||
ClaudeBox runs Claude Code CLI natively inside the BoxLite micro-VM. This means planning-with-files hooks execute exactly as they do on your local machine:
|
||||
|
||||
| Hook | Trigger | What It Does |
|
||||
|------|---------|--------------|
|
||||
| **PreToolUse** | Before Write, Edit, Bash, Read, Glob, Grep | Reads first 30 lines of `task_plan.md` — keeps goals in attention |
|
||||
| **PostToolUse** | After Write, Edit | Reminds agent to update plan status after file changes |
|
||||
| **Stop** | When agent finishes | Runs completion check script before stopping |
|
||||
|
||||
The hook scripts need to be injected alongside SKILL.md. See the full example in `examples/boxlite/quickstart.py` for how to include them.
|
||||
|
||||
---
|
||||
|
||||
## Session Recovery
|
||||
|
||||
When your context fills up and you run `/clear`, the skill recovers the previous session automatically on next activation. Inside a ClaudeBox session, run manually:
|
||||
|
||||
```python
|
||||
async with ClaudeBox.reconnect("my-project") as box:
|
||||
await box.code(
|
||||
"Run session catchup: python3 ~/.claude/skills/planning-with-files/scripts/session-catchup.py $(pwd)"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Snapshots
|
||||
|
||||
BoxLite supports checkpointing. Snapshot before a risky implementation phase:
|
||||
|
||||
```python
|
||||
from claudebox import ClaudeBox
|
||||
from boxlite import Box
|
||||
|
||||
async def main():
|
||||
async with ClaudeBox(session_id="risky-refactor", skills=[PLANNING_SKILL]) as box:
|
||||
# Phase 1 complete — snapshot before the destructive refactor
|
||||
await box.box.snapshot("pre-refactor")
|
||||
|
||||
result = await box.code("Refactor the database layer")
|
||||
|
||||
if "error" in result.response.lower():
|
||||
await box.box.restore("pre-refactor")
|
||||
print("Rolled back to pre-refactor snapshot")
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill not activating inside the VM?
|
||||
|
||||
The skill file must be at `/root/.claude/skills/planning-with-files/SKILL.md` inside the VM. Verify by injecting a validation step:
|
||||
|
||||
```python
|
||||
result = await box.code("ls ~/.claude/skills/planning-with-files/")
|
||||
print(result.response)
|
||||
```
|
||||
|
||||
### Hooks not running?
|
||||
|
||||
The Stop hook script (`check-complete.sh`) must also be injected. Add it to the `files` dict in your Skill object. See `examples/boxlite/quickstart.py` for the full implementation.
|
||||
|
||||
### Docker not found?
|
||||
|
||||
ClaudeBox uses Docker to pull OCI images for the VM. Install Docker Desktop (macOS/Windows) or Docker Engine (Linux). The sandbox itself does not run as a Docker container — Docker is only used for image management.
|
||||
|
||||
### BoxLite not available on Windows host?
|
||||
|
||||
BoxLite requires Linux KVM (Linux) or Hypervisor.framework (macOS). On Windows, use WSL2 with KVM enabled.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [BoxLite documentation](https://docs.boxlite.ai)
|
||||
- [ClaudeBox repository](https://github.com/boxlite-ai/claudebox)
|
||||
- [boxlite-mcp](https://github.com/boxlite-labs/boxlite-mcp) — MCP server for BoxLite sandboxing
|
||||
- [Quick Start Guide](quickstart.md)
|
||||
- [Workflow Diagram](workflow.md)
|
||||
- [Author: @OthmanAdi](https://github.com/OthmanAdi)
|
||||
+36
-6
@@ -6,14 +6,44 @@ planning-with-files works with Codex as a personal skill in `~/.codex/skills/`.
|
||||
|
||||
## Installation
|
||||
|
||||
See [.codex/INSTALL.md](../.codex/INSTALL.md) for detailed installation instructions.
|
||||
Codex auto-discovers skills from `.codex/skills/` directories. Two installation methods:
|
||||
|
||||
### Quick Install
|
||||
### Method 1: Workspace Installation (Recommended)
|
||||
|
||||
Share the skill with your entire team by adding it to your repository:
|
||||
|
||||
```bash
|
||||
# In your project repository
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git /tmp/planning-with-files
|
||||
|
||||
# Copy the Codex skill to your repo
|
||||
cp -r /tmp/planning-with-files/.codex .
|
||||
|
||||
# Commit to share with team
|
||||
git add .codex/
|
||||
git commit -m "Add planning-with-files skill for Codex"
|
||||
git push
|
||||
|
||||
# Clean up
|
||||
rm -rf /tmp/planning-with-files
|
||||
```
|
||||
|
||||
Now everyone on your team using Codex will have access to the skill!
|
||||
|
||||
### Method 2: Personal Installation
|
||||
|
||||
Install just for yourself:
|
||||
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git /tmp/planning-with-files
|
||||
|
||||
# Copy to your personal Codex skills folder
|
||||
mkdir -p ~/.codex/skills
|
||||
cd ~/.codex/skills
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
cp -r /tmp/planning-with-files/.codex/skills/planning-with-files ~/.codex/skills/
|
||||
|
||||
# Clean up
|
||||
rm -rf /tmp/planning-with-files
|
||||
```
|
||||
|
||||
## Usage with Superpowers
|
||||
@@ -33,7 +63,7 @@ Add to your `~/.codex/AGENTS.md`:
|
||||
|
||||
<IMPORTANT>
|
||||
For complex tasks (3+ steps, research, projects):
|
||||
1. Read skill: `cat ~/.codex/skills/planning-with-files/planning-with-files/SKILL.md`
|
||||
1. Read skill: `cat ~/.codex/skills/planning-with-files/SKILL.md`
|
||||
2. Create task_plan.md, findings.md, progress.md in your project directory
|
||||
3. Follow 3-file pattern throughout the task
|
||||
</IMPORTANT>
|
||||
@@ -42,7 +72,7 @@ For complex tasks (3+ steps, research, projects):
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
ls -la ~/.codex/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
ls -la ~/.codex/skills/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
## Learn More
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
# GitHub Copilot Setup
|
||||
|
||||
Setting up planning-with-files for GitHub Copilot (CLI, VS Code, and Coding Agent).
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- GitHub Copilot with hooks support enabled
|
||||
- For VS Code: Copilot Chat extension v1.109.3+
|
||||
- For CLI: GitHub Copilot CLI with agent mode
|
||||
- For Coding Agent: Works automatically with `.github/hooks/`
|
||||
|
||||
---
|
||||
|
||||
## Installation Methods
|
||||
|
||||
### Method 1: Repository-Level (Recommended)
|
||||
Copy both the `.github/hooks/` directory and the `skills/planning-with-files/` directory into your project:
|
||||
|
||||
```bash
|
||||
# Copy hooks (required — Copilot hook configuration and scripts)
|
||||
cp -r .github/hooks/ your-project/.github/hooks/
|
||||
|
||||
# Copy skills (required — templates, session-catchup script, and SKILL.md)
|
||||
cp -r skills/planning-with-files/ your-project/.github/skills/planning-with-files/
|
||||
|
||||
# Make scripts executable (macOS/Linux)
|
||||
chmod +x your-project/.github/hooks/scripts/*.sh
|
||||
```
|
||||
|
||||
Hooks will auto-activate for all team members. This works across Copilot CLI, VS Code, and the Coding Agent.
|
||||
|
||||
### Method 2: Manual Setup
|
||||
1. Create `.github/hooks/planning-with-files.json`
|
||||
2. Copy hook scripts to `.github/hooks/scripts/`
|
||||
3. Copy `skills/planning-with-files/` to `.github/skills/planning-with-files/` (templates, session-catchup script)
|
||||
4. Ensure all scripts are executable (`chmod +x .github/hooks/scripts/*.sh`)
|
||||
|
||||
---
|
||||
|
||||
## What the Hooks Do
|
||||
|
||||
| Hook | Purpose | Behavior |
|
||||
|------|---------|----------|
|
||||
| `sessionStart` | Initialization | Recovers previous context via session-catchup |
|
||||
| `preToolUse` | Context injection | Reads `task_plan.md` before tool operations |
|
||||
| `postToolUse` | Update reminders | Prompts to update plan after file edits |
|
||||
| `agentStop` | Completion check | Verifies if all phases are complete before stopping |
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
.github/
|
||||
└── hooks/
|
||||
├── planning-with-files.json # Hook configuration
|
||||
└── scripts/
|
||||
├── session-start.sh # Session initialization
|
||||
├── session-start.ps1
|
||||
├── pre-tool-use.sh # Plan context injection
|
||||
├── pre-tool-use.ps1
|
||||
├── post-tool-use.sh # Update reminders
|
||||
├── post-tool-use.ps1
|
||||
├── agent-stop.sh # Completion verification
|
||||
└── agent-stop.ps1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Session starts**: The `session-catchup` script runs. This recovers previous context if you cleared your session.
|
||||
2. **Before tool use**: The `pre-tool-use` hook injects `task_plan.md` into the context. This keeps goals visible to the agent.
|
||||
3. **After file edits**: A reminder appears after any write or edit operations. This helps ensure the plan stays updated.
|
||||
4. **Agent tries to stop**: The `agent-stop` hook checks the phase status in `task_plan.md`. It prevents stopping if tasks remain.
|
||||
|
||||
---
|
||||
|
||||
## Differences from Claude Code Plugin
|
||||
|
||||
- **Hook Configuration**: Claude Code uses `SKILL.md` frontmatter hooks. Copilot uses the `.github/hooks/` JSON configuration file.
|
||||
- **Stop Hook**: Claude's `Stop` hook corresponds to Copilot's `agentStop`.
|
||||
- **Planning Files**: Both use the same core files (task_plan.md, findings.md, progress.md).
|
||||
- **Protocol**: Hook scripts are adapted for Copilot's stdin JSON and stdout JSON protocol.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Hooks not running**: Check file permissions. Ensure the `.github/hooks/` directory is committed to your repository.
|
||||
- **Scripts failing**: Verify that `bash` and `python3` are available in your system PATH.
|
||||
- **Windows**: PowerShell scripts (.ps1) are used automatically on Windows systems.
|
||||
- **VS Code**: You might need to enable hooks in your Copilot Chat extension settings.
|
||||
|
||||
---
|
||||
|
||||
## Compatibility
|
||||
|
||||
This setup works across the entire GitHub Copilot ecosystem:
|
||||
|
||||
- GitHub Copilot CLI (terminal)
|
||||
- VS Code Copilot Chat (agent mode)
|
||||
- GitHub Copilot Coding Agent (github.com)
|
||||
+105
-76
@@ -1,113 +1,148 @@
|
||||
# Cursor IDE Setup
|
||||
|
||||
How to use planning-with-files with Cursor IDE.
|
||||
How to use planning-with-files with Cursor IDE — now with full hook support.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Option 1: Copy rules directory
|
||||
### Option 1: Copy .cursor directory (Recommended)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
cp -r planning-with-files/.cursor .cursor
|
||||
```
|
||||
|
||||
This copies the skill files, hooks config, and hook scripts to your project.
|
||||
|
||||
### Option 2: Manual setup
|
||||
|
||||
Create `.cursor/rules/planning-with-files.mdc` in your project with the content from this repo.
|
||||
1. Copy `.cursor/skills/planning-with-files/` to your project
|
||||
2. Copy `.cursor/hooks.json` to your project
|
||||
3. Copy `.cursor/hooks/` directory to your project
|
||||
|
||||
---
|
||||
|
||||
## Important Limitations
|
||||
## Hooks Support
|
||||
|
||||
> **Note:** Hooks (PreToolUse, PostToolUse, Stop, SessionStart) are **Claude Code specific** and will NOT work in Cursor.
|
||||
Cursor now supports hooks natively via `.cursor/hooks.json`. This skill includes three hooks that mirror the Claude Code experience:
|
||||
|
||||
### What works in Cursor:
|
||||
| Hook | Purpose | Cursor Feature |
|
||||
|------|---------|----------------|
|
||||
| `preToolUse` | Re-reads task_plan.md before tool operations | Keeps goals in context |
|
||||
| `postToolUse` | Reminds to update plan after file edits | Prevents forgetting updates |
|
||||
| `stop` | Checks if all phases are complete | **Auto-continues** if incomplete |
|
||||
|
||||
- Core 3-file planning pattern
|
||||
- Templates (task_plan.md, findings.md, progress.md)
|
||||
- All planning rules and guidelines
|
||||
- The 2-Action Rule
|
||||
- The 3-Strike Error Protocol
|
||||
- Read vs Write Decision Matrix
|
||||
### How the Stop Hook Works
|
||||
|
||||
### What doesn't work in Cursor:
|
||||
The stop hook is the most powerful feature. When the agent tries to stop:
|
||||
|
||||
- SessionStart hook (no startup notification)
|
||||
- PreToolUse hook (no automatic plan re-reading)
|
||||
- PostToolUse hook (no automatic reminders)
|
||||
- Stop hook (no automatic completion verification)
|
||||
1. It checks `task_plan.md` for phase completion status
|
||||
2. If all phases are complete → allows the agent to stop
|
||||
3. If phases are incomplete → sends a `followup_message` that auto-prompts the agent to keep working
|
||||
|
||||
---
|
||||
This means the agent **cannot stop until all phases are done** (up to `loop_limit` of 3 retries).
|
||||
|
||||
## Manual Workflow for Cursor
|
||||
|
||||
Since hooks don't work in Cursor, you'll need to follow the pattern manually:
|
||||
|
||||
### 1. Create planning files first
|
||||
|
||||
Before any complex task:
|
||||
```
|
||||
Create task_plan.md, findings.md, and progress.md using the planning-with-files templates.
|
||||
```
|
||||
|
||||
### 2. Re-read plan before decisions
|
||||
|
||||
Periodically ask:
|
||||
```
|
||||
Please read task_plan.md to refresh the goals before continuing.
|
||||
```
|
||||
|
||||
### 3. Update files after phases
|
||||
|
||||
After completing work:
|
||||
```
|
||||
Update task_plan.md to mark this phase complete.
|
||||
Update progress.md with what was done.
|
||||
```
|
||||
|
||||
### 4. Verify completion manually
|
||||
|
||||
Before finishing:
|
||||
```
|
||||
Check task_plan.md - are all phases marked complete?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cursor Rules File
|
||||
|
||||
The `.cursor/rules/planning-with-files.mdc` file contains all the planning guidelines formatted for Cursor's rules system.
|
||||
|
||||
### File location
|
||||
### Hook Files
|
||||
|
||||
```
|
||||
your-project/
|
||||
├── .cursor/
|
||||
│ └── rules/
|
||||
│ └── planning-with-files.mdc
|
||||
├── task_plan.md
|
||||
│ ├── hooks.json ← Hook configuration
|
||||
│ ├── hooks/
|
||||
│ │ ├── pre-tool-use.sh ← Pre-tool-use script
|
||||
│ │ ├── post-tool-use.sh ← Post-tool-use script
|
||||
│ │ ├── stop.sh ← Completion check script
|
||||
│ │ ├── pre-tool-use.ps1 ← PowerShell versions
|
||||
│ │ ├── post-tool-use.ps1
|
||||
│ │ └── stop.ps1
|
||||
│ └── skills/
|
||||
│ └── planning-with-files/
|
||||
│ ├── SKILL.md
|
||||
│ ├── examples.md
|
||||
│ ├── reference.md
|
||||
│ └── templates/
|
||||
├── task_plan.md ← Your planning files (created per task)
|
||||
├── findings.md
|
||||
├── progress.md
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Activating rules
|
||||
---
|
||||
|
||||
Cursor automatically loads rules from `.cursor/rules/` when you open a project.
|
||||
## Windows Setup
|
||||
|
||||
The default `hooks.json` uses bash scripts (works on macOS, Linux, and Windows with Git Bash).
|
||||
|
||||
**If you need native PowerShell**, rename the config files:
|
||||
|
||||
```powershell
|
||||
# Back up the default config
|
||||
Rename-Item .cursor\hooks.json hooks.unix.json
|
||||
|
||||
# Use the PowerShell config
|
||||
Rename-Item .cursor\hooks.windows.json hooks.json
|
||||
```
|
||||
|
||||
The `.cursor/hooks.windows.json` file uses PowerShell to execute the `.ps1` hook scripts directly.
|
||||
|
||||
---
|
||||
|
||||
## What Each Hook Does
|
||||
|
||||
### PreToolUse Hook
|
||||
|
||||
**Triggers:** Before Write, Edit, Shell, or Read operations
|
||||
|
||||
**What it does:** Reads the first 30 lines of `task_plan.md` and logs them to stderr for context. Always returns `{"decision": "allow"}` — it never blocks tools.
|
||||
|
||||
**Claude Code equivalent:** `cat task_plan.md 2>/dev/null | head -30 || true`
|
||||
|
||||
### PostToolUse Hook
|
||||
|
||||
**Triggers:** After Write or Edit operations
|
||||
|
||||
**What it does:** Outputs a reminder to update `task_plan.md` if a phase was completed.
|
||||
|
||||
**Claude Code equivalent:** `echo '[planning-with-files] File updated...'`
|
||||
|
||||
### Stop Hook
|
||||
|
||||
**Triggers:** When the agent tries to stop working
|
||||
|
||||
**What it does:**
|
||||
1. Counts total phases (`### Phase` headers) in `task_plan.md`
|
||||
2. Counts completed phases (supports both `**Status:** complete` and `[complete]` formats)
|
||||
3. If incomplete, returns `followup_message` to auto-continue
|
||||
4. Capped at 3 retries via `loop_limit` to prevent infinite loops
|
||||
|
||||
**Claude Code equivalent:** `scripts/check-complete.sh` — but Cursor's version is **more powerful** because it can auto-continue the agent instead of just reporting status.
|
||||
|
||||
---
|
||||
|
||||
## Skill Files
|
||||
|
||||
The `.cursor/skills/planning-with-files/SKILL.md` file contains all the planning guidelines:
|
||||
|
||||
- Core 3-file planning pattern
|
||||
- Templates (task_plan.md, findings.md, progress.md)
|
||||
- The 2-Action Rule
|
||||
- The 3-Strike Error Protocol
|
||||
- Read vs Write Decision Matrix
|
||||
|
||||
Cursor automatically loads skills from `.cursor/skills/` when you open a project.
|
||||
|
||||
---
|
||||
|
||||
## Templates
|
||||
|
||||
The templates in `skills/planning-with-files/templates/` work in Cursor:
|
||||
The templates in `.cursor/skills/planning-with-files/templates/` are used when starting a new task:
|
||||
|
||||
- `task_plan.md` - Phase tracking template
|
||||
- `findings.md` - Research storage template
|
||||
- `progress.md` - Session logging template
|
||||
|
||||
Copy them to your project root when starting a new task.
|
||||
The agent copies these to your project root when starting a new planning session.
|
||||
|
||||
---
|
||||
|
||||
@@ -115,27 +150,21 @@ Copy them to your project root when starting a new task.
|
||||
|
||||
1. **Pin the planning files:** Keep task_plan.md open in a split view for easy reference.
|
||||
|
||||
2. **Add to .cursorrules:** You can also add planning guidelines to your project's `.cursorrules` file.
|
||||
2. **Trust the hooks:** The stop hook will prevent premature completion — you don't need to manually verify phase status.
|
||||
|
||||
3. **Use explicit prompts:** Since there's no auto-detection, be explicit:
|
||||
3. **Use explicit prompts for complex tasks:**
|
||||
```
|
||||
This is a complex task. Let's use the planning-with-files pattern.
|
||||
Start by creating task_plan.md with the goal and phases.
|
||||
```
|
||||
|
||||
4. **Check status regularly:** Without the Stop hook, manually verify completion before finishing.
|
||||
4. **Check hook logs:** If hooks aren't working, check Cursor's output panel for hook execution logs.
|
||||
|
||||
---
|
||||
|
||||
## Migrating from Cursor to Claude Code
|
||||
## Compatibility with Claude Code
|
||||
|
||||
If you want full hook support, consider using Claude Code CLI:
|
||||
|
||||
1. Install Claude Code
|
||||
2. Run `/plugin install planning-with-files@planning-with-files`
|
||||
3. All hooks will work automatically
|
||||
|
||||
Your existing planning files (task_plan.md, etc.) are compatible with both.
|
||||
Your planning files (task_plan.md, findings.md, progress.md) are fully compatible between Cursor and Claude Code. You can switch between them without any changes to your planning files.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+7
-57
@@ -5,7 +5,7 @@ Planning with Files is fully supported on Kilo Code through native integration.
|
||||
## Quick Start
|
||||
|
||||
1. Open your project in Kilo Code
|
||||
2. Rules load automatically from global (`~/.kilocode/rules/`) or project (`.kilocode/rules/`) directories
|
||||
2. Skills load automatically from global (`~/.kilocode/skills/`) or project (`.kilocode/skills/`) directories
|
||||
3. Start a complex task — Kilo Code will automatically create planning files
|
||||
|
||||
## Installation
|
||||
@@ -21,11 +21,7 @@ git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
|
||||
# Copy the skill to Kilo Code's skills directory
|
||||
mkdir -p .kilocode/skills
|
||||
cp -r planning-with-files/skills/planning-with-files .kilocode/skills/planning-with-files
|
||||
|
||||
# Copy the rules file (optional, but recommended)
|
||||
mkdir -p .kilocode/rules
|
||||
cp planning-with-files/.kilocode/rules/planning-with-files.md .kilocode/rules/planning-with-files.md
|
||||
cp -r planning-with-files/.kilocode/skills/planning-with-files .kilocode/skills/planning-with-files
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
@@ -35,15 +31,7 @@ git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
|
||||
# Copy the skill to Kilo Code's skills directory
|
||||
New-Item -ItemType Directory -Force -Path .kilocode\skills
|
||||
Copy-Item -Recurse -Force planning-with-files\skills\planning-with-files .kilocode\skills\planning-with-files
|
||||
|
||||
# Copy the rules file (optional, but recommended)
|
||||
New-Item -ItemType Directory -Force -Path .kilocode\rules
|
||||
Copy-Item -Force planning-with-files\.kilocode\rules\planning-with-files.md .kilocode\rules\planning-with-files.md
|
||||
|
||||
# Copy PowerShell scripts (optional, but recommended)
|
||||
Copy-Item -Force planning-with-files\scripts\init-session.ps1 .kilocode\skills\planning-with-files\scripts\init-session.ps1
|
||||
Copy-Item -Force planning-with-files\scripts\check-complete.ps1 .kilocode\skills\planning-with-files\scripts\check-complete.ps1
|
||||
Copy-Item -Recurse -Force planning-with-files\.kilocode\skills\planning-with-files .kilocode\skills\planning-with-files
|
||||
```
|
||||
|
||||
### Manual Installation (Project-Level)
|
||||
@@ -54,26 +42,14 @@ Copy the skill directory to your project:
|
||||
```bash
|
||||
# From the cloned repository
|
||||
mkdir -p .kilocode/skills
|
||||
cp -r planning-with-files/skills/planning-with-files .kilocode/skills/planning-with-files
|
||||
|
||||
# Copy the rules file (optional, but recommended)
|
||||
mkdir -p .kilocode/rules
|
||||
cp planning-with-files/.kilocode/rules/planning-with-files.md .kilocode/rules/planning-with-files.md
|
||||
cp -r planning-with-files/.kilocode/skills/planning-with-files .kilocode/skills/planning-with-files
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
# From the cloned repository
|
||||
New-Item -ItemType Directory -Force -Path .kilocode\skills
|
||||
Copy-Item -Recurse -Force planning-with-files\skills\planning-with-files .kilocode\skills\planning-with-files
|
||||
|
||||
# Copy the rules file (optional, but recommended)
|
||||
New-Item -ItemType Directory -Force -Path .kilocode\rules
|
||||
Copy-Item -Force planning-with-files\.kilocode\rules\planning-with-files.md .kilocode\rules\planning-with-files.md
|
||||
|
||||
# Copy PowerShell scripts (optional, but recommended)
|
||||
Copy-Item -Force planning-with-files\scripts\init-session.ps1 .kilocode\skills\planning-with-files\scripts\init-session.ps1
|
||||
Copy-Item -Force planning-with-files\scripts\check-complete.ps1 .kilocode\skills\planning-with-files\scripts\check-complete.ps1
|
||||
Copy-Item -Recurse -Force planning-with-files\.kilocode\skills\planning-with-files .kilocode\skills\planning-with-files
|
||||
```
|
||||
|
||||
### Global Installation (User-Level)
|
||||
@@ -84,26 +60,14 @@ To make the skill available across all projects:
|
||||
```bash
|
||||
# Copy to global skills directory
|
||||
mkdir -p ~/.kilocode/skills
|
||||
cp -r planning-with-files/skills/planning-with-files ~/.kilocode/skills/planning-with-files
|
||||
|
||||
# Copy the rules file (optional, but recommended)
|
||||
mkdir -p ~/.kilocode/rules
|
||||
cp planning-with-files/.kilocode/rules/planning-with-files.md ~/.kilocode/rules/planning-with-files.md
|
||||
cp -r planning-with-files/.kilocode/skills/planning-with-files ~/.kilocode/skills/planning-with-files
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
# Copy to global skills directory (replace YourUsername with your actual username)
|
||||
New-Item -ItemType Directory -Force -Path C:\Users\YourUsername\.kilocode\skills
|
||||
Copy-Item -Recurse -Force planning-with-files\skills\planning-with-files C:\Users\YourUsername\.kilocode\skills\planning-with-files
|
||||
|
||||
# Copy the rules file (optional, but recommended)
|
||||
New-Item -ItemType Directory -Force -Path C:\Users\YourUsername\.kilocode\rules
|
||||
Copy-Item -Force planning-with-files\.kilocode\rules\planning-with-files.md C:\Users\YourUsername\.kilocode\rules\planning-with-files.md
|
||||
|
||||
# Copy PowerShell scripts (optional, but recommended)
|
||||
Copy-Item -Force planning-with-files\scripts\init-session.ps1 C:\Users\YourUsername\.kilocode\skills\planning-with-files\scripts\init-session.ps1
|
||||
Copy-Item -Force planning-with-files\scripts\check-complete.ps1 C:\Users\YourUsername\.kilocode\skills\planning-with-files\scripts\check-complete.ps1
|
||||
Copy-Item -Recurse -Force planning-with-files\.kilocode\skills\planning-with-files C:\Users\YourUsername\.kilocode\skills\planning-with-files
|
||||
```
|
||||
|
||||
### Verifying Installation
|
||||
@@ -113,7 +77,6 @@ After installation, verify the skill is loaded:
|
||||
1. **Restart Kilo Code** (if needed)
|
||||
2. Ask the agent: "Do you have access to the planning-with-files skill?"
|
||||
3. The agent should confirm the skill is loaded
|
||||
4. Rules also load automatically from `~/.kilocode/rules/planning-with-files.md` (global) or `.kilocode/rules/planning-with-files.md` (project)
|
||||
|
||||
**Testing PowerShell Scripts (Windows):**
|
||||
|
||||
@@ -131,10 +94,6 @@ The scripts should create `task_plan.md`, `findings.md`, and `progress.md` files
|
||||
|
||||
### File Structure
|
||||
|
||||
The installation consists of the skill directory and the rules file:
|
||||
|
||||
**Skill Directory:**
|
||||
|
||||
```
|
||||
~/.kilocode/skills/planning-with-files/ (Global)
|
||||
OR
|
||||
@@ -153,21 +112,12 @@ OR
|
||||
└── check-complete.ps1 # Windows (PowerShell)
|
||||
```
|
||||
|
||||
**Rules File:**
|
||||
|
||||
```
|
||||
~/.kilocode/rules/planning-with-files.md (Global)
|
||||
OR
|
||||
.kilocode/rules/planning-with-files.md (Project)
|
||||
```
|
||||
|
||||
**Important**: The `name` field in `SKILL.md` must match the directory name (`planning-with-files`).
|
||||
|
||||
## File Locations
|
||||
|
||||
| Type | Global Location | Project Location |
|
||||
|------|-----------------|------------------|
|
||||
| **Rules** | `~/.kilocode/rules/planning-with-files.md` | `.kilocode/rules/planning-with-files.md` |
|
||||
| **Skill** | `~/.kilocode/skills/planning-with-files/SKILL.md` | `.kilocode/skills/planning-with-files/SKILL.md` |
|
||||
| **Templates** | `~/.kilocode/skills/planning-with-files/templates/` | `.kilocode/skills/planning-with-files/templates/` |
|
||||
| **Scripts (Unix/Linux/macOS)** | `~/.kilocode/skills/planning-with-files/scripts/*.sh` | `.kilocode/skills/planning-with-files/scripts/*.sh` |
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
# Mastra Code Setup
|
||||
|
||||
Using planning-with-files with [Mastra Code](https://code.mastra.ai/).
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Mastra Code auto-discovers skills from `.mastracode/skills/` directories. It also has built-in Claude Code compatibility, so it reads `.claude/skills/` too — but the dedicated `.mastracode/` integration gives you native hooks support.
|
||||
|
||||
## Installation
|
||||
|
||||
### Method 1: Workspace Installation (Recommended)
|
||||
|
||||
Share the skill with your entire team by adding it to your repository:
|
||||
|
||||
```bash
|
||||
# In your project repository
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git /tmp/planning-with-files
|
||||
|
||||
# Copy the Mastra Code skill to your repo
|
||||
cp -r /tmp/planning-with-files/.mastracode .
|
||||
|
||||
# Commit to share with team
|
||||
git add .mastracode/
|
||||
git commit -m "Add planning-with-files skill for Mastra Code"
|
||||
git push
|
||||
|
||||
# Clean up
|
||||
rm -rf /tmp/planning-with-files
|
||||
```
|
||||
|
||||
Now everyone on your team using Mastra Code will have access to the skill.
|
||||
|
||||
### Method 2: Personal Installation
|
||||
|
||||
Install just for yourself:
|
||||
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git /tmp/planning-with-files
|
||||
|
||||
# Copy skill to your personal Mastra Code skills folder
|
||||
mkdir -p ~/.mastracode/skills
|
||||
cp -r /tmp/planning-with-files/.mastracode/skills/planning-with-files ~/.mastracode/skills/
|
||||
|
||||
# Copy hooks (required for plan enforcement)
|
||||
# If you already have ~/.mastracode/hooks.json, merge the entries manually
|
||||
cp /tmp/planning-with-files/.mastracode/hooks.json ~/.mastracode/hooks.json
|
||||
|
||||
# Clean up
|
||||
rm -rf /tmp/planning-with-files
|
||||
```
|
||||
|
||||
> **Note:** If you already have a `~/.mastracode/hooks.json`, do not overwrite it. Instead, merge the PreToolUse, PostToolUse, and Stop entries from the skill's hooks.json into your existing file.
|
||||
|
||||
### Verification
|
||||
|
||||
```bash
|
||||
ls -la ~/.mastracode/skills/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
Restart your Mastra Code session. The skill auto-activates when you work on complex tasks.
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
### Hooks (via hooks.json)
|
||||
|
||||
Mastra Code uses a separate `hooks.json` file for lifecycle hooks. This is different from Claude Code, which defines hooks in SKILL.md frontmatter. Mastra Code reads hooks from:
|
||||
|
||||
1. `.mastracode/hooks.json` (project-level, highest priority)
|
||||
2. `~/.mastracode/hooks.json` (global)
|
||||
|
||||
This integration includes a pre-configured `hooks.json` with all three hooks:
|
||||
|
||||
| Hook | Matcher | What It Does |
|
||||
|------|---------|--------------|
|
||||
| **PreToolUse** | Write, Edit, Bash, Read, Glob, Grep | Reads first 30 lines of `task_plan.md` to keep goals in attention |
|
||||
| **PostToolUse** | Write, Edit | Reminds you to update plan status after file changes |
|
||||
| **Stop** | (all) | Runs `check-complete.sh` to verify all phases are done |
|
||||
|
||||
### Auto-Activation
|
||||
|
||||
The skill activates when you:
|
||||
- Mention "complex task" or "multi-step project"
|
||||
- Ask to "plan out" or "break down" work
|
||||
- Request help organizing or tracking progress
|
||||
- Start research tasks requiring >5 tool calls
|
||||
|
||||
### The Three Files
|
||||
|
||||
Once activated, the skill creates:
|
||||
|
||||
| File | Purpose | Location |
|
||||
|------|---------|----------|
|
||||
| `task_plan.md` | Phases, progress, decisions | Your project root |
|
||||
| `findings.md` | Research, discoveries | Your project root |
|
||||
| `progress.md` | Session log, test results | Your project root |
|
||||
|
||||
---
|
||||
|
||||
## Claude Code Compatibility
|
||||
|
||||
Mastra Code reads from `.claude/skills/` as a fallback. If you already have planning-with-files installed for Claude Code, it will work — but the dedicated `.mastracode/` installation gives you:
|
||||
|
||||
- Native hooks via `hooks.json` (PreToolUse, PostToolUse, Stop)
|
||||
- Correct script path resolution for Mastra Code directories
|
||||
- No path conflicts with Claude Code plugin root
|
||||
|
||||
---
|
||||
|
||||
## Session Recovery
|
||||
|
||||
When your context fills up and you run `/clear`, the skill can recover your previous session.
|
||||
|
||||
Run manually:
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
python3 ~/.mastracode/skills/planning-with-files/scripts/session-catchup.py "$(pwd)"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# Windows PowerShell
|
||||
python "$env:USERPROFILE\.mastracode\skills\planning-with-files\scripts\session-catchup.py" (Get-Location)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Team Workflow
|
||||
|
||||
### Workspace Skills (Recommended)
|
||||
|
||||
With workspace installation (`.mastracode/skills/`):
|
||||
- Everyone on team has the skill
|
||||
- Consistent planning across projects
|
||||
- Version controlled with your repo
|
||||
- Changes sync via git
|
||||
|
||||
### Personal Skills
|
||||
|
||||
With personal installation (`~/.mastracode/skills/`):
|
||||
- Use across all your projects
|
||||
- Keep it even if you switch teams
|
||||
- Not shared with teammates
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill Not Activating?
|
||||
|
||||
1. Verify the file exists: `ls ~/.mastracode/skills/planning-with-files/SKILL.md`
|
||||
2. Restart Mastra Code — skills are scanned on startup
|
||||
3. Use trigger phrases: "plan out", "break down", "organize", "track progress"
|
||||
|
||||
### Hooks Not Running?
|
||||
|
||||
Mastra Code reads hooks from `hooks.json`, not from SKILL.md frontmatter. Verify:
|
||||
|
||||
1. Check that `.mastracode/hooks.json` exists in your project root (workspace install) or `~/.mastracode/hooks.json` (personal install)
|
||||
2. Verify the file contains PreToolUse, PostToolUse, and Stop entries
|
||||
3. Restart Mastra Code after adding or modifying hooks.json
|
||||
|
||||
### Already Using Claude Code?
|
||||
|
||||
No conflict. Mastra Code checks `.mastracode/skills/` first, then falls back to `.claude/skills/`. You can have both installed.
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
- **GitHub Issues:** https://github.com/OthmanAdi/planning-with-files/issues
|
||||
- **Mastra Code Docs:** https://code.mastra.ai/configuration
|
||||
- **Author:** [@OthmanAdi](https://github.com/OthmanAdi)
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Quick Start Guide](quickstart.md)
|
||||
- [Workflow Diagram](workflow.md)
|
||||
- [Manus Principles](../skills/planning-with-files/reference.md)
|
||||
- [Real Examples](../skills/planning-with-files/examples.md)
|
||||
+45
-2
@@ -42,15 +42,58 @@ cat ~/.config/opencode/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
|
||||
## oh-my-opencode Compatibility
|
||||
|
||||
If using oh-my-opencode, ensure planning-with-files is not in the `disabled_skills` array:
|
||||
oh-my-opencode has Claude Code compatibility for skills. To use planning-with-files with oh-my-opencode:
|
||||
|
||||
### Step 1: Install the skill
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/skills/planning-with-files
|
||||
cp -r .opencode/skills/planning-with-files/* ~/.config/opencode/skills/planning-with-files/
|
||||
```
|
||||
|
||||
### Step 2: Configure oh-my-opencode
|
||||
|
||||
Add the skill to your `~/.config/opencode/oh-my-opencode.json` (or `.opencode/oh-my-opencode.json` for project-level):
|
||||
|
||||
**~/.config/opencode/oh-my-opencode.json:**
|
||||
```json
|
||||
{
|
||||
"skills": {
|
||||
"sources": [
|
||||
{ "path": "~/.config/opencode/skills/planning-with-files", "recursive": false }
|
||||
],
|
||||
"enable": ["planning-with-files"]
|
||||
},
|
||||
"disabled_skills": []
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Verify loading
|
||||
|
||||
Ask the agent: "Do you have access to the planning-with-files skill? Can you create task_plan.md?"
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If the agent forgets the planning rules:
|
||||
|
||||
1. **Check skill is loaded**: The skill should appear in oh-my-opencode's recognized skills
|
||||
2. **Explicit invocation**: Tell the agent "Use the planning-with-files skill for this task"
|
||||
3. **Check for conflicts**: If using superpowers plugin alongside oh-my-opencode, choose one method:
|
||||
- Use oh-my-opencode's native skill loading (recommended)
|
||||
- OR use superpowers' `use_skill` tool, but not both
|
||||
|
||||
## Known Limitations
|
||||
|
||||
### Session Catchup
|
||||
|
||||
The `session-catchup.py` script currently has limited support for OpenCode due to different session storage formats:
|
||||
|
||||
- **Claude Code**: Uses `.jsonl` files at `~/.claude/projects/`
|
||||
- **OpenCode**: Uses `.json` files at `~/.local/share/opencode/storage/session/`
|
||||
|
||||
When you run `/clear` in OpenCode, session catchup will detect OpenCode and show a message. **Workaround**: Manually read `task_plan.md`, `progress.md`, and `findings.md` to catch up after clearing context.
|
||||
|
||||
Full OpenCode session parsing support is planned for a future release.
|
||||
|
||||
## Verification
|
||||
|
||||
**Global:**
|
||||
|
||||
+11
-10
@@ -4,24 +4,25 @@ Follow these 5 steps to use the planning-with-files pattern.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Create Your Planning Files
|
||||
## Step 1: Invoke the Skill and Describe Your Task
|
||||
|
||||
**When:** Before starting any work on a complex task
|
||||
|
||||
**Action:** Create all three files using the templates:
|
||||
**Action:** Invoke the skill (e.g., `/plan` or `/planning-with-files:start`) and describe what you want to accomplish. The AI will create all three planning files in your project directory:
|
||||
|
||||
- `task_plan.md` — Phases and progress tracking
|
||||
- `findings.md` — Research and discoveries
|
||||
- `progress.md` — Session log and test results
|
||||
|
||||
If you invoke the skill without a task description, the AI will ask you what you'd like to plan.
|
||||
|
||||
**Manual alternative:** If you prefer to create files yourself:
|
||||
```bash
|
||||
# Option 1: Use the init script (if available)
|
||||
# Use the init script
|
||||
./scripts/init-session.sh
|
||||
|
||||
# Option 2: Copy templates manually
|
||||
cp templates/task_plan.md task_plan.md
|
||||
cp templates/findings.md findings.md
|
||||
cp templates/progress.md progress.md
|
||||
# Then fill in the Goal section in task_plan.md
|
||||
```
|
||||
|
||||
**Update:** Fill in the Goal section in `task_plan.md` with your task description.
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Plan Your Phases
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# BoxLite Examples
|
||||
|
||||
Working examples for running planning-with-files inside [BoxLite](https://boxlite.ai) micro-VM sandboxes via [ClaudeBox](https://github.com/boxlite-ai/claudebox).
|
||||
|
||||
## Files
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `quickstart.py` | Full Python example — loads planning-with-files as a ClaudeBox Skill, runs a planning session inside a BoxLite VM |
|
||||
|
||||
## Requirements
|
||||
|
||||
```bash
|
||||
pip install claudebox
|
||||
export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
python quickstart.py
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
See [docs/boxlite.md](../../docs/boxlite.md) for the full integration guide.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user