Compare commits

...
8 Commits
Author SHA1 Message Date
OthmanAdi 4206e0e5e8 docs: update CONTRIBUTORS, CHANGELOG, README for v2.27.0
- Add @EListenX (Yi Chenxi) to Major Contributions in CONTRIBUTORS.md
- Add v2.27.0 entry to CHANGELOG.md (Kiro Agent Skill support)
- Update README version table, Kiro badge, and platform description
- Update last-updated date to March 20, 2026
2026-03-20 23:23:17 +01:00
OthmanAdi 6dc9e3f44a feat(kiro): add Agent Skill layout under .kiro/skills/ (#112)
Adds full Kiro Agent Skill support with proper .kiro/skills/ layout,
bootstrap scripts, steering integration, and planning templates.
Replaces the old .kiro/scripts/ and .kiro/steering/ approach.
Also updates docs/kiro.md and sync-ide-folders.py skip list.

Contributed by Yi Chenxi (@EListenX)
2026-03-20 23:19:32 +01:00
OthmanAdi bedf1a291a docs: bump version to v2.26.2 for YAML frontmatter fix 2026-03-20 16:37:15 +01:00
OthmanAdi 3ff59de625 fix: replace --- with === in hook commands to prevent YAML frontmatter breakage
The literal '---' inside the UserPromptSubmit hook command was parsed as
a YAML document separator, corrupting the skill description and causing
PreToolUse:Write hook errors. Changed to '=== recent progress ===' in
all 11 affected files.
2026-03-20 16:34:30 +01:00
OthmanAdi d2b75b8177 docs: bump version to v2.26.1 for session catchup fix 2026-03-20 15:24:21 +01:00
OthmanAdi 66a0cb510f test: add automated session recovery test (11 assertions)
Tests hook output, path sanitization, UTF-8 encoding, and separator
handling without requiring interactive /clear. Run with:
  bash tests/test_clear_recovery.sh
2026-03-20 15:15:55 +01:00
OthmanAdi 9aee747eb0 fix: session catchup after /clear — path sanitization + content injection (#106)
Two root causes found:

1. Path sanitization bug: On Windows, Git Bash passes /c/Users/... but
   Claude Code stores sessions under C--Users-... The script converted
   to -c-Users-... which never matched. Added normalize_path() that
   converts Git Bash paths to Windows paths before sanitizing.

2. Hook was advisory, not actionable: UserPromptSubmit hook only said
   "read task_plan.md" — after /clear the agent has no context and may
   ignore text advice. Now the hook dumps actual content: first 50 lines
   of task_plan.md + last 20 lines of progress.md. The agent gets the
   plan state injected directly, no tool calls needed.

Also fixed: UTF-8 encoding for session file parsing on Windows (cp1252
default caused UnicodeDecodeError on non-ASCII content).

Changes synced to all IDE variants via sync-ide-folders.py.
2026-03-20 09:35:41 +01:00
v-yichenxi 402d929564 feat(kiro): add Kiro Agent Skill and align Mastra/Cursor hooks (v2.23.1)
IDE hook follow-up (v2.23.0 gaps):

- Mastra Code: hooks.json is the hook source — add UserPromptSubmit, refresh PostToolUse.
- Cursor: .cursor/hooks/ — add user-prompt-submit, update post-tool-use and stop scripts.

Kiro workspace skill:

- Add .kiro/skills/planning-with-files/ (SKILL.md, references, templates, scripts).
- Bootstrap creates .kiro/plan and auto steering planning-context.md (#[[file:]]).
- Add session-catchup.py; check-complete/bootstrap for sh and PowerShell.
- Remove duplicate .kiro/scripts and always-on steering; sync script skips .kiro.
- Update docs/kiro.md and README (Kiro = Agent Skill + Steering).
2026-03-20 11:40:00 +08:00
44 changed files with 1624 additions and 588 deletions
@@ -7,7 +7,7 @@ hooks:
UserPromptSubmit:
- hooks:
- type: command
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding.'; fi"
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] ACTIVE PLAN — current state:'; head -50 task_plan.md; echo ''; echo '=== recent progress ==='; tail -20 progress.md 2>/dev/null; echo ''; echo '[planning-with-files] Read findings.md for research context. Continue from the current phase.'; fi"
PreToolUse:
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
hooks:
@@ -17,12 +17,42 @@ from typing import List, Dict, Optional, Tuple
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
def normalize_path(project_path: str) -> str:
"""Normalize project path to match Claude Code's internal representation.
Claude Code stores session directories using the Windows-native path
(e.g., C:\\Users\\...) sanitized with separators replaced by dashes.
Git Bash passes /c/Users/... which produces a DIFFERENT sanitized
string. This function converts Git Bash paths to Windows paths first.
"""
p = project_path
# Git Bash / MSYS2: /c/Users/... -> C:/Users/...
if len(p) >= 3 and p[0] == '/' and p[2] == '/':
p = p[1].upper() + ':' + p[2:]
# Resolve to absolute path to handle relative paths and symlinks
try:
resolved = str(Path(p).resolve())
# On Windows, resolve() returns C:\Users\... which is what we want
if os.name == 'nt' or '\\' in resolved:
p = resolved
except (OSError, ValueError):
pass
return p
def get_project_dir(project_path: str) -> Tuple[Optional[Path], Optional[str]]:
"""Resolve session storage path for the current runtime variant."""
sanitized = project_path.replace('/', '-')
if not sanitized.startswith('-'):
sanitized = '-' + sanitized
normalized = normalize_path(project_path)
# Claude Code's sanitization: replace path separators and : with -
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
# Strip leading dash if present (Unix absolute paths start with /)
if sanitized.startswith('-'):
sanitized = sanitized[1:]
claude_path = Path.home() / '.claude' / 'projects' / sanitized
@@ -50,7 +80,7 @@ def get_sessions_sorted(project_dir: Path) -> List[Path]:
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:
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
+1 -1
View File
@@ -7,7 +7,7 @@ hooks:
UserPromptSubmit:
- hooks:
- type: command
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding.'; fi"
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] ACTIVE PLAN — current state:'; head -50 task_plan.md; echo ''; echo '=== recent progress ==='; tail -20 progress.md 2>/dev/null; echo ''; echo '[planning-with-files] Read findings.md for research context. Continue from the current phase.'; fi"
PreToolUse:
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
hooks:
@@ -17,12 +17,42 @@ from typing import List, Dict, Optional, Tuple
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
def normalize_path(project_path: str) -> str:
"""Normalize project path to match Claude Code's internal representation.
Claude Code stores session directories using the Windows-native path
(e.g., C:\\Users\\...) sanitized with separators replaced by dashes.
Git Bash passes /c/Users/... which produces a DIFFERENT sanitized
string. This function converts Git Bash paths to Windows paths first.
"""
p = project_path
# Git Bash / MSYS2: /c/Users/... -> C:/Users/...
if len(p) >= 3 and p[0] == '/' and p[2] == '/':
p = p[1].upper() + ':' + p[2:]
# Resolve to absolute path to handle relative paths and symlinks
try:
resolved = str(Path(p).resolve())
# On Windows, resolve() returns C:\Users\... which is what we want
if os.name == 'nt' or '\\' in resolved:
p = resolved
except (OSError, ValueError):
pass
return p
def get_project_dir(project_path: str) -> Tuple[Optional[Path], Optional[str]]:
"""Resolve session storage path for the current runtime variant."""
sanitized = project_path.replace('/', '-')
if not sanitized.startswith('-'):
sanitized = '-' + sanitized
normalized = normalize_path(project_path)
# Claude Code's sanitization: replace path separators and : with -
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
# Strip leading dash if present (Unix absolute paths start with /)
if sanitized.startswith('-'):
sanitized = sanitized[1:]
claude_path = Path.home() / '.claude' / 'projects' / sanitized
@@ -50,7 +80,7 @@ def get_sessions_sorted(project_dir: Path) -> List[Path]:
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:
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
@@ -17,12 +17,42 @@ from typing import List, Dict, Optional, Tuple
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
def normalize_path(project_path: str) -> str:
"""Normalize project path to match Claude Code's internal representation.
Claude Code stores session directories using the Windows-native path
(e.g., C:\\Users\\...) sanitized with separators replaced by dashes.
Git Bash passes /c/Users/... which produces a DIFFERENT sanitized
string. This function converts Git Bash paths to Windows paths first.
"""
p = project_path
# Git Bash / MSYS2: /c/Users/... -> C:/Users/...
if len(p) >= 3 and p[0] == '/' and p[2] == '/':
p = p[1].upper() + ':' + p[2:]
# Resolve to absolute path to handle relative paths and symlinks
try:
resolved = str(Path(p).resolve())
# On Windows, resolve() returns C:\Users\... which is what we want
if os.name == 'nt' or '\\' in resolved:
p = resolved
except (OSError, ValueError):
pass
return p
def get_project_dir(project_path: str) -> Tuple[Optional[Path], Optional[str]]:
"""Resolve session storage path for the current runtime variant."""
sanitized = project_path.replace('/', '-')
if not sanitized.startswith('-'):
sanitized = '-' + sanitized
normalized = normalize_path(project_path)
# Claude Code's sanitization: replace path separators and : with -
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
# Strip leading dash if present (Unix absolute paths start with /)
if sanitized.startswith('-'):
sanitized = sanitized[1:]
claude_path = Path.home() / '.claude' / 'projects' / sanitized
@@ -50,7 +80,7 @@ def get_sessions_sorted(project_dir: Path) -> List[Path]:
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:
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
+11 -3
View File
@@ -1,8 +1,16 @@
# planning-with-files: User prompt submit hook for Cursor (PowerShell)
# Reminds the agent about active planning files on every user message.
# Critical for session recovery after context reset.
# Injects plan context on every user message.
# Critical for session recovery after /clear — dumps actual content, not just advice.
if (Test-Path "task_plan.md") {
Write-Output "[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding."
Write-Output "[planning-with-files] ACTIVE PLAN — current state:"
Get-Content "task_plan.md" -TotalCount 50 -Encoding UTF8
Write-Output ""
Write-Output "=== recent progress ==="
if (Test-Path "progress.md") {
Get-Content "progress.md" -Tail 20 -Encoding UTF8
}
Write-Output ""
Write-Output "[planning-with-files] Read findings.md for research context. Continue from the current phase."
}
exit 0
+9 -3
View File
@@ -1,9 +1,15 @@
#!/bin/bash
# planning-with-files: User prompt submit hook for Cursor
# Reminds the agent about active planning files on every user message.
# Critical for session recovery after context reset.
# Injects plan context on every user message.
# Critical for session recovery after /clear — dumps actual content, not just advice.
if [ -f task_plan.md ]; then
echo "[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding."
echo "[planning-with-files] ACTIVE PLAN — current state:"
head -50 task_plan.md
echo ""
echo "=== recent progress ==="
tail -20 progress.md 2>/dev/null
echo ""
echo "[planning-with-files] Read findings.md for research context. Continue from the current phase."
fi
exit 0
+1 -1
View File
@@ -7,7 +7,7 @@ hooks:
UserPromptSubmit:
- hooks:
- type: command
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding.'; fi"
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] ACTIVE PLAN — current state:'; head -50 task_plan.md; echo ''; echo '=== recent progress ==='; tail -20 progress.md 2>/dev/null; echo ''; echo '[planning-with-files] Read findings.md for research context. Continue from the current phase.'; fi"
PreToolUse:
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
hooks:
+1 -1
View File
@@ -7,7 +7,7 @@ hooks:
UserPromptSubmit:
- hooks:
- type: command
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding.'; fi"
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] ACTIVE PLAN — current state:'; head -50 task_plan.md; echo ''; echo '=== recent progress ==='; tail -20 progress.md 2>/dev/null; echo ''; echo '[planning-with-files] Read findings.md for research context. Continue from the current phase.'; fi"
PreToolUse:
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
hooks:
@@ -17,12 +17,42 @@ from typing import List, Dict, Optional, Tuple
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
def normalize_path(project_path: str) -> str:
"""Normalize project path to match Claude Code's internal representation.
Claude Code stores session directories using the Windows-native path
(e.g., C:\\Users\\...) sanitized with separators replaced by dashes.
Git Bash passes /c/Users/... which produces a DIFFERENT sanitized
string. This function converts Git Bash paths to Windows paths first.
"""
p = project_path
# Git Bash / MSYS2: /c/Users/... -> C:/Users/...
if len(p) >= 3 and p[0] == '/' and p[2] == '/':
p = p[1].upper() + ':' + p[2:]
# Resolve to absolute path to handle relative paths and symlinks
try:
resolved = str(Path(p).resolve())
# On Windows, resolve() returns C:\Users\... which is what we want
if os.name == 'nt' or '\\' in resolved:
p = resolved
except (OSError, ValueError):
pass
return p
def get_project_dir(project_path: str) -> Tuple[Optional[Path], Optional[str]]:
"""Resolve session storage path for the current runtime variant."""
sanitized = project_path.replace('/', '-')
if not sanitized.startswith('-'):
sanitized = '-' + sanitized
normalized = normalize_path(project_path)
# Claude Code's sanitization: replace path separators and : with -
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
# Strip leading dash if present (Unix absolute paths start with /)
if sanitized.startswith('-'):
sanitized = sanitized[1:]
claude_path = Path.home() / '.claude' / 'projects' / sanitized
@@ -50,7 +80,7 @@ def get_sessions_sorted(project_dir: Path) -> List[Path]:
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:
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
@@ -17,12 +17,42 @@ from typing import List, Dict, Optional, Tuple
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
def normalize_path(project_path: str) -> str:
"""Normalize project path to match Claude Code's internal representation.
Claude Code stores session directories using the Windows-native path
(e.g., C:\\Users\\...) sanitized with separators replaced by dashes.
Git Bash passes /c/Users/... which produces a DIFFERENT sanitized
string. This function converts Git Bash paths to Windows paths first.
"""
p = project_path
# Git Bash / MSYS2: /c/Users/... -> C:/Users/...
if len(p) >= 3 and p[0] == '/' and p[2] == '/':
p = p[1].upper() + ':' + p[2:]
# Resolve to absolute path to handle relative paths and symlinks
try:
resolved = str(Path(p).resolve())
# On Windows, resolve() returns C:\Users\... which is what we want
if os.name == 'nt' or '\\' in resolved:
p = resolved
except (OSError, ValueError):
pass
return p
def get_project_dir(project_path: str) -> Tuple[Optional[Path], Optional[str]]:
"""Resolve session storage path for the current runtime variant."""
sanitized = project_path.replace('/', '-')
if not sanitized.startswith('-'):
sanitized = '-' + sanitized
normalized = normalize_path(project_path)
# Claude Code's sanitization: replace path separators and : with -
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
# Strip leading dash if present (Unix absolute paths start with /)
if sanitized.startswith('-'):
sanitized = sanitized[1:]
claude_path = Path.home() / '.claude' / 'projects' / sanitized
@@ -50,7 +80,7 @@ def get_sessions_sorted(project_dir: Path) -> List[Path]:
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:
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
-44
View File
@@ -1,44 +0,0 @@
# 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 + '). If the user has additional work, add new phases to task_plan.md before starting.')
} else {
Write-Host ('[planning-with-files] Task in progress (' + $COMPLETE + '/' + $TOTAL + ' phases complete). Update progress.md before stopping.')
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
-46
View File
@@ -1,46 +0,0 @@
#!/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). If the user has additional work, add new phases to task_plan.md before starting."
else
echo "[planning-with-files] Task in progress ($COMPLETE/$TOTAL phases complete). Update progress.md before stopping."
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
-120
View File
@@ -1,120 +0,0 @@
# 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"
-120
View File
@@ -1,120 +0,0 @@
#!/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"
+123
View File
@@ -0,0 +1,123 @@
---
name: planning-with-files
description: Manus-style file-based planning for complex tasks. Creates and maintains task_plan.md, findings.md, and progress.md under .kiro/plan/. Use when planning, breaking down work, resuming a multi-step task, tracking phases, or restoring context after compaction. Trigger phrases include start planning, continue task, resume work, current phase, restore context.
license: MIT
compatibility: Requires a POSIX shell or PowerShell, Python 3 for session-catchup, and read/write access to the workspace. See Kiro Agent Skills — https://kiro.dev/docs/skills/
allowed-tools: shell read write
metadata:
version: "3.0.0-kiro"
integration: kiro
---
# Planning with Files (Kiro)
Work like **Manus**: use persistent markdown as your **working memory on disk** while the model context behaves like volatile RAM. Deep background: [references/manus-principles.md](references/manus-principles.md).
Kiro complements this with:
- **Agent Skills** (this file) — progressive disclosure when the task matches the description.
- **Steering** — after bootstrap, `.kiro/steering/planning-context.md` uses `inclusion: auto` and `#[[file:…]]` live references ([Steering docs](https://kiro.dev/docs/steering/)).
**Hooks are not bundled:** project-level hooks affect every chat in the workspace. Prefer this skill + steering + the reminder block below.
---
## STEP 0 — Bootstrap (once per workspace)
From the **workspace root**:
```bash
sh .kiro/skills/planning-with-files/assets/scripts/bootstrap.sh
```
Windows (PowerShell):
```powershell
pwsh -ExecutionPolicy Bypass -File .kiro/skills/planning-with-files/assets/scripts/bootstrap.ps1
```
Creates:
- `.kiro/plan/task_plan.md`, `findings.md`, `progress.md`
- `.kiro/steering/planning-context.md` (auto + `#[[file:.kiro/plan/…]]`)
Idempotent: existing files are not overwritten.
**Import as a workspace skill (optional):** Kiro → *Agent Steering & Skills* → *Import a skill* → choose this `planning-with-files` folder ([Skills docs](https://kiro.dev/docs/skills/)).
---
## STEP 1 — Persistent reminder (after skill activation)
Append the following block to the **end of your reply**, and repeat it at the **end of subsequent replies** while this planning session is active:
> `[Planning Active]` Before each turn, read `.kiro/plan/task_plan.md` and `.kiro/plan/progress.md` to restore context.
---
## STEP 2 — Read plan every turn (while active)
1. Read `.kiro/plan/task_plan.md` — goal, phases, status
2. Read `.kiro/plan/progress.md` — recent actions
3. Use `.kiro/plan/findings.md` for research and decisions
If `.kiro/plan/` is missing, run STEP 0.
---
## STEP 3 — Session catchup (after a long gap or suspected drift)
Summaries + file mtimes (compare with `git diff --stat` if needed):
```bash
$(command -v python3 || command -v python) \
.kiro/skills/planning-with-files/assets/scripts/session-catchup.py "$(pwd)"
```
Windows:
```powershell
python .kiro/skills/planning-with-files/assets/scripts/session-catchup.py (Get-Location)
```
Then reconcile planning files with the actual codebase.
---
## Optional — Phase checklist
From workspace root (defaults to `.kiro/plan/task_plan.md`):
```bash
sh .kiro/skills/planning-with-files/assets/scripts/check-complete.sh
```
```powershell
pwsh -File .kiro/skills/planning-with-files/assets/scripts/check-complete.ps1
```
---
## Rules (summary)
Full detail: [references/planning-rules.md](references/planning-rules.md). Inline template skeletons: [references/planning-templates.md](references/planning-templates.md).
1. **Plan first** — no open-ended multi-step work without `task_plan.md`.
2. **2-action rule** — after every two view/search/browser steps, write to `findings.md`.
3. **Read before big decisions** — refresh `task_plan.md` into attention.
4. **Update after each phase** — `in_progress` → `complete`, log errors.
5. **Never repeat the same failed action** — change tool, approach, or assumptions.
## When to use
**Use:** multi-step work, research, refactors, anything that spans many tool calls.
**Skip:** one-off questions, tiny single-file edits.
## Anti-patterns
| Avoid | Prefer |
|-------|--------|
| Goals only in chat | `.kiro/plan/task_plan.md` |
| Silent retries | Log errors; change approach |
| Huge pasted logs in chat | Append to `findings.md` or `progress.md` |
@@ -0,0 +1,53 @@
# Bootstrap planning-with-files into the current workspace (idempotent).
# Run from the workspace root:
# pwsh -File .kiro/skills/planning-with-files/assets/scripts/bootstrap.ps1
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$SkillDir = (Resolve-Path (Join-Path $ScriptDir "..\..")).Path
$TemplatesSrc = Join-Path $SkillDir "assets\templates"
$ProjectDir = if ($env:PLANNING_PROJECT_ROOT) { $env:PLANNING_PROJECT_ROOT } else { (Get-Location).Path }
$PlanDest = Join-Path $ProjectDir ".kiro\plan"
$SteeringDest = Join-Path $ProjectDir ".kiro\steering"
Write-Host ""
Write-Host "planning-with-files (Kiro) — bootstrap"
Write-Host "Project: $ProjectDir"
Write-Host ""
Write-Host "[ Planning files → $PlanDest ]"
New-Item -ItemType Directory -Force -Path $PlanDest | Out-Null
$installed = 0
$skipped = 0
foreach ($tpl in @("task_plan.md", "findings.md", "progress.md")) {
$dest = Join-Path $PlanDest $tpl
$src = Join-Path $TemplatesSrc $tpl
if (Test-Path $dest) {
Write-Host " SKIP $tpl"
$skipped++
} else {
Copy-Item -Path $src -Destination $dest
Write-Host " OK $tpl"
$installed++
}
}
Write-Host ""
Write-Host "[ Steering → $SteeringDest ]"
New-Item -ItemType Directory -Force -Path $SteeringDest | Out-Null
$contextSrc = Join-Path $TemplatesSrc "planning-context.md"
$contextDest = Join-Path $SteeringDest "planning-context.md"
if (Test-Path $contextDest) {
Write-Host " SKIP planning-context.md"
} else {
Copy-Item -Path $contextSrc -Destination $contextDest
Write-Host " OK planning-context.md (auto inclusion + #[[file:]] references)"
}
Write-Host ""
Write-Host "Done. Planning files: .kiro/plan/"
Write-Host "Optional: import this folder as a Kiro workspace skill (Agent Steering & Skills → Import)."
Write-Host ""
@@ -0,0 +1,52 @@
#!/usr/bin/env sh
# Bootstrap planning-with-files into the current workspace (idempotent).
# Run from the workspace root: sh .kiro/skills/planning-with-files/assets/scripts/bootstrap.sh
set -e
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
SKILL_DIR="$(CDPATH= cd -- "$SCRIPT_DIR/../.." && pwd)"
TEMPLATES_SRC="$SKILL_DIR/assets/templates"
PROJECT_DIR="${PLANNING_PROJECT_ROOT:-$(pwd)}"
PLAN_DEST="$PROJECT_DIR/.kiro/plan"
STEERING_DEST="$PROJECT_DIR/.kiro/steering"
echo ""
echo "planning-with-files (Kiro) — bootstrap"
echo "Project: $PROJECT_DIR"
echo ""
echo "[ Planning files → $PLAN_DEST ]"
mkdir -p "$PLAN_DEST"
installed_files=0
skipped_files=0
for tpl in task_plan.md findings.md progress.md; do
dest="$PLAN_DEST/$tpl"
if [ -f "$dest" ]; then
echo " SKIP $tpl"
skipped_files=$((skipped_files + 1))
else
cp "$TEMPLATES_SRC/$tpl" "$dest"
echo " OK $tpl"
installed_files=$((installed_files + 1))
fi
done
echo ""
echo "[ Steering → $STEERING_DEST ]"
mkdir -p "$STEERING_DEST"
CONTEXT_SRC="$TEMPLATES_SRC/planning-context.md"
CONTEXT_DEST="$STEERING_DEST/planning-context.md"
if [ -f "$CONTEXT_DEST" ]; then
echo " SKIP planning-context.md"
else
cp "$CONTEXT_SRC" "$CONTEXT_DEST"
echo " OK planning-context.md (auto inclusion + #[[file:]] references)"
fi
echo ""
echo "Done. Planning files: .kiro/plan/"
echo "Optional: import this folder as a Kiro workspace skill (Agent Steering & Skills → Import)."
echo ""
@@ -0,0 +1,36 @@
# Report phase completion status for task_plan.md (stdout only, always exit 0).
# Default plan path: .kiro/plan/task_plan.md (relative to current directory).
param(
[string]$PlanFile = ".kiro/plan/task_plan.md"
)
if (-not (Test-Path $PlanFile)) {
Write-Host "[planning-with-files] No task plan at $PlanFile — run bootstrap or specify path."
exit 0
}
$content = Get-Content $PlanFile -Raw
$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
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-Host "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)."
} else {
Write-Host "[planning-with-files] In progress ($COMPLETE/$TOTAL phases complete)."
if ($IN_PROGRESS -gt 0) {
Write-Host "[planning-with-files] $IN_PROGRESS phase(s) in_progress."
}
if ($PENDING -gt 0) {
Write-Host "[planning-with-files] $PENDING phase(s) pending."
}
}
exit 0
@@ -0,0 +1,39 @@
#!/usr/bin/env sh
# Report phase completion status for task_plan.md (stdout only, always exit 0).
# Default plan path: .kiro/plan/task_plan.md (relative to current directory).
PLAN_FILE="${1:-.kiro/plan/task_plan.md}"
if [ ! -f "$PLAN_FILE" ]; then
echo "[planning-with-files] No task plan at $PLAN_FILE — run bootstrap or specify path."
exit 0
fi
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" 2>/dev/null || echo 0)
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" 2>/dev/null || echo 0)
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" 2>/dev/null || echo 0)
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" 2>/dev/null || echo 0)
if [ "$COMPLETE" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ] && [ "$PENDING" -eq 0 ]; then
COMPLETE=$(grep -c "\[complete\]" "$PLAN_FILE" 2>/dev/null || echo 0)
IN_PROGRESS=$(grep -c "\[in_progress\]" "$PLAN_FILE" 2>/dev/null || echo 0)
PENDING=$(grep -c "\[pending\]" "$PLAN_FILE" 2>/dev/null || echo 0)
fi
: "${TOTAL:=0}"
: "${COMPLETE:=0}"
: "${IN_PROGRESS:=0}"
: "${PENDING:=0}"
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
echo "[planning-with-files] ALL PHASES COMPLETE ($COMPLETE/$TOTAL)."
else
echo "[planning-with-files] In progress ($COMPLETE/$TOTAL phases complete)."
if [ "$IN_PROGRESS" -gt 0 ]; then
echo "[planning-with-files] $IN_PROGRESS phase(s) in_progress."
fi
if [ "$PENDING" -gt 0 ]; then
echo "[planning-with-files] $PENDING phase(s) pending."
fi
fi
exit 0
@@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""
Session catchup for Kiro / planning-with-files.
Scans .kiro/plan/ for planning files and prints a short report (mtime + summary)
so the agent can re-orient after a context reset or long gap.
Usage:
python3 session-catchup.py [project_dir]
"""
from __future__ import annotations
import datetime
import os
import sys
def read_file_safe(path: str) -> str | None:
try:
with open(path, "r", encoding="utf-8") as f:
return f.read()
except OSError:
return None
def get_mtime_str(path: str) -> str:
try:
mtime = os.path.getmtime(path)
return datetime.datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S")
except OSError:
return "unknown"
def extract_section(content: str, heading: str) -> str | None:
lines = content.splitlines()
in_section = False
result: list[str] = []
for line in lines:
if line.startswith("## " + heading) or line.startswith("# " + heading):
in_section = True
continue
if in_section:
if line.startswith("## ") or line.startswith("# "):
break
result.append(line)
text = "\n".join(result).strip()
return text[:500] if text else None
def main() -> None:
project_dir = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else os.getcwd())
plan_dir = os.path.join(project_dir, ".kiro", "plan")
plan_files = {
"task_plan.md": os.path.join(plan_dir, "task_plan.md"),
"findings.md": os.path.join(plan_dir, "findings.md"),
"progress.md": os.path.join(plan_dir, "progress.md"),
}
found = {name: path for name, path in plan_files.items() if os.path.exists(path)}
if not found:
print("[planning-with-files] No planning files under .kiro/plan/. Run bootstrap first.")
sys.exit(0)
print("=" * 60)
print("[planning-with-files] SESSION CATCHUP REPORT")
print(f"Project: {project_dir}")
print("=" * 60)
for name, path in found.items():
mtime = get_mtime_str(path)
content = read_file_safe(path)
print(f"\n--- {name} (last modified: {mtime}) ---")
if not content:
print(" (empty)")
continue
if name == "task_plan.md":
goal = extract_section(content, "Goal")
current_phase = extract_section(content, "Current Phase")
if goal:
print(f" Goal: {goal[:200]}")
if current_phase:
print(f" Current Phase: {current_phase[:100]}")
for line in content.splitlines():
if "Status:" in line:
print(f" {line.strip()}")
elif name == "findings.md":
requirements = extract_section(content, "Requirements")
if requirements:
lines = [
l
for l in requirements.splitlines()
if l.strip() and not l.strip().startswith("<!--")
]
preview = "\n ".join(lines[:5])
if preview:
print(f" Requirements:\n {preview}")
elif name == "progress.md":
lines = [
l
for l in content.splitlines()
if l.strip() and not l.strip().startswith("<!--")
]
last_lines = lines[-8:] if len(lines) >= 8 else lines
if last_lines:
print(" Recent entries:")
for line in last_lines:
print(f" {line}")
print("\n" + "=" * 60)
print("Next: read the full files under .kiro/plan/, then `git diff --stat` if repo drift is suspected.")
print("=" * 60)
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,13 @@
---
inclusion: auto
name: planning-context
description: Active multi-step task context. Include when the user asks to continue a task, resume work, check current phase, show progress, or work on any ongoing planned project.
---
## Current Task Plan
#[[file:.kiro/plan/task_plan.md]]
## Recent Progress
#[[file:.kiro/plan/progress.md]]
@@ -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
@@ -0,0 +1,121 @@
# Manus context engineering (reference)
This workflow is inspired by **Manus**-style context engineering: treat markdown on disk as durable working memory while the model context window behaves like volatile RAM.
**Kiro layout:** planning files live under **`.kiro/plan/`** (not the project root). See [Kiro Steering — file references](https://kiro.dev/docs/steering/) for `#[[file:path]]` live includes.
---
# 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 `.kiro/plan/task_plan.md` before major decisions. Goals appear in the attention window.
### 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)
```
### Strategy 2: Context Isolation (Multi-Agent)
Multi-agent setups can isolate exploration in separate contexts while persisting shared state in files (e.g. under `.kiro/plan/`).
### Strategy 3: Context Offloading
- Store full results in the filesystem, not only in context
- Progressive disclosure: load information only as needed
---
## File Types (Kiro paths)
| File | Purpose |
|------|---------|
| `.kiro/plan/task_plan.md` | Phase tracking, progress |
| `.kiro/plan/findings.md` | Discoveries, decisions |
| `.kiro/plan/progress.md` | Session log |
---
## Source
Manus context engineering blog:
https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus
@@ -0,0 +1,45 @@
# Planning rules (full reference)
All paths below are under the workspace root.
## The 3-Strike Error Protocol
```
ATTEMPT 1: Diagnose & Fix
ATTEMPT 2: Alternative approach (never repeat the exact same failing action)
ATTEMPT 3: Broader rethink; update the plan if needed
AFTER 3 FAILURES: Escalate to the user with evidence
```
## Read vs Write Decision Matrix
| Situation | Action |
|-----------|--------|
| Just wrote a file | Do not re-read unless stale |
| Viewed image/PDF/browser output | Write to `.kiro/plan/findings.md` immediately |
| Starting a new phase | Read `.kiro/plan/task_plan.md` and `findings.md` |
| Resuming after a gap | Read all files under `.kiro/plan/` |
## The 5-Question Reboot Test
| Question | Answer source |
|----------|----------------|
| Where am I? | `.kiro/plan/task_plan.md` |
| Where am I going? | Remaining phases in `task_plan.md` |
| What's the goal? | Goal section in `task_plan.md` |
| What have I learned? | `.kiro/plan/findings.md` |
| What have I done? | `.kiro/plan/progress.md` |
## Phase status values
- `pending` — not started
- `in_progress` — active
- `complete` — done
## Error log (in `task_plan.md`)
```markdown
## Errors Encountered
| Error | Attempt | Resolution |
|-------|---------|------------|
```
@@ -1,8 +1,20 @@
# Planning File Templates
# Planning file templates (reference)
Copy these templates to your project root when starting complex tasks.
Bootstrap copies the canonical templates from `assets/templates/` into `.kiro/plan/`. This page is a **compact reference** (inline skeletons) when you need to paste structure without opening those files.
## task_plan.md Template
To use as a Kiro **manual steering** document, copy this file to `.kiro/steering/planning-templates.md` and add front matter:
```yaml
---
inclusion: manual
name: planning-templates
description: Markdown templates for task_plan, findings, and progress.
---
```
---
## task_plan.md
```markdown
# Task Plan
@@ -38,7 +50,7 @@ Phase X: [Name] - [Status]
|-------|---------|------------|
```
## findings.md Template
## findings.md
```markdown
# Findings
@@ -61,7 +73,7 @@ Phase X: [Name] - [Status]
- [Resource 2](url)
```
## progress.md Template
## progress.md
```markdown
# Progress Log
-71
View File
@@ -1,71 +0,0 @@
# Planning Rules
Critical rules for effective file-based planning.
## Rule 1: Create Plan First
Never start a complex task without `task_plan.md`. Non-negotiable.
## Rule 2: The 2-Action Rule
After every 2 view/browser/search operations, IMMEDIATELY save key findings to `findings.md`.
This prevents visual/multimodal information from being lost.
## Rule 3: Read Before Decide
Before major decisions, read `task_plan.md`. This keeps goals in your attention window.
## Rule 4: Update After Act
After completing any phase:
- Mark phase status: `in_progress` → `complete`
- Log any errors encountered
- Note files created/modified
## Rule 5: Log ALL Errors
Every error goes in the plan file with this format:
```markdown
## Errors Encountered
| Error | Attempt | Resolution |
|-------|---------|------------|
| FileNotFoundError | 1 | Created default config |
| API timeout | 2 | Added retry logic |
```
## Rule 6: Never Repeat Failures
If an action failed, the next action must be different. Track what you tried and 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
→ 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
```
## 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 |
-43
View File
@@ -1,43 +0,0 @@
# Planning with Files Workflow
Use persistent markdown files as your "working memory on disk" — the Manus pattern that made a $2B acquisition.
## The Core Pattern
```
Context Window = RAM (volatile, limited)
Filesystem = Disk (persistent, unlimited)
→ Anything important gets written to disk.
```
## Required Files
Create these three files in your project root before starting complex tasks:
| 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 |
## Quick Start
1. **Create `task_plan.md`** with goal, phases, and status tracking
2. **Create `findings.md`** for research and technical decisions
3. **Create `progress.md`** for session logging
4. **Re-read plan before decisions** — keeps goals in attention
5. **Update after each phase** — mark complete, log errors
## When to Use This Pattern
**Use 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
+2 -2
View File
@@ -2,9 +2,9 @@
"UserPromptSubmit": [
{
"type": "command",
"command": "if [ -f task_plan.md ]; then echo '[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding.'; fi",
"command": "if [ -f task_plan.md ]; then echo '[planning-with-files] ACTIVE PLAN — current state:'; head -50 task_plan.md; echo ''; echo '=== recent progress ==='; tail -20 progress.md 2>/dev/null; echo ''; echo '[planning-with-files] Read findings.md for research context. Continue from the current phase.'; fi",
"timeout": 5000,
"description": "Remind agent about active plan on every user message for session recovery"
"description": "Inject plan context on every user message for session recovery after /clear"
}
],
"PreToolUse": [
@@ -7,7 +7,7 @@ hooks:
UserPromptSubmit:
- hooks:
- type: command
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding.'; fi"
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] ACTIVE PLAN — current state:'; head -50 task_plan.md; echo ''; echo '=== recent progress ==='; tail -20 progress.md 2>/dev/null; echo ''; echo '[planning-with-files] Read findings.md for research context. Continue from the current phase.'; fi"
PreToolUse:
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
hooks:
@@ -7,7 +7,7 @@ hooks:
UserPromptSubmit:
- hooks:
- type: command
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding.'; fi"
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] ACTIVE PLAN — current state:'; head -50 task_plan.md; echo ''; echo '=== recent progress ==='; tail -20 progress.md 2>/dev/null; echo ''; echo '[planning-with-files] Read findings.md for research context. Continue from the current phase.'; fi"
PreToolUse:
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
hooks:
@@ -17,12 +17,42 @@ from typing import List, Dict, Optional, Tuple
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
def normalize_path(project_path: str) -> str:
"""Normalize project path to match Claude Code's internal representation.
Claude Code stores session directories using the Windows-native path
(e.g., C:\\Users\\...) sanitized with separators replaced by dashes.
Git Bash passes /c/Users/... which produces a DIFFERENT sanitized
string. This function converts Git Bash paths to Windows paths first.
"""
p = project_path
# Git Bash / MSYS2: /c/Users/... -> C:/Users/...
if len(p) >= 3 and p[0] == '/' and p[2] == '/':
p = p[1].upper() + ':' + p[2:]
# Resolve to absolute path to handle relative paths and symlinks
try:
resolved = str(Path(p).resolve())
# On Windows, resolve() returns C:\Users\... which is what we want
if os.name == 'nt' or '\\' in resolved:
p = resolved
except (OSError, ValueError):
pass
return p
def get_project_dir(project_path: str) -> Tuple[Optional[Path], Optional[str]]:
"""Resolve session storage path for the current runtime variant."""
sanitized = project_path.replace('/', '-')
if not sanitized.startswith('-'):
sanitized = '-' + sanitized
normalized = normalize_path(project_path)
# Claude Code's sanitization: replace path separators and : with -
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
# Strip leading dash if present (Unix absolute paths start with /)
if sanitized.startswith('-'):
sanitized = sanitized[1:]
claude_path = Path.home() / '.claude' / 'projects' / sanitized
@@ -50,7 +80,7 @@ def get_sessions_sorted(project_dir: Path) -> List[Path]:
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:
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
+21
View File
@@ -2,6 +2,27 @@
All notable changes to this project will be documented in this file.
## [2.27.0] - 2026-03-20
### Added
- **Kiro Agent Skill support** (PR #112 by @EListenX)
- Full `.kiro/skills/planning-with-files/` layout with SKILL.md, bootstrap scripts, templates, references
- Bootstrap creates `.kiro/plan/` for planning files and `.kiro/steering/planning-context.md` with `#[[file:]]` live references
- Includes session-catchup.py and check-complete scripts adapted for Kiro's `.kiro/plan/` path
- Replaces the old `.kiro/scripts/` and `.kiro/steering/` approach with proper Agent Skill format
### Changed
- Updated `scripts/sync-ide-folders.py` to skip `.kiro` (Kiro uses its own skill layout)
- Rewrote `docs/kiro.md` to reflect new Agent Skill approach
### Thanks
- @EListenX (Yi Chenxi) for the thorough Kiro integration with proper Agent Skill format
---
## [2.23.0] - 2026-03-16
### Fixed
+8 -1
View File
@@ -59,6 +59,13 @@ These amazing people have contributed code, documentation, or significant improv
- Created `docs/codebuddy.md` installation guide
- **Impact:** Expands IDE support to CodeBuddy ecosystem
- **[@EListenX](https://github.com/EListenX)** (Yi Chenxi) - [PR #112](https://github.com/OthmanAdi/planning-with-files/pull/112)
- Added full Kiro Agent Skill support under `.kiro/skills/planning-with-files/`
- Created bootstrap scripts, steering integration with `#[[file:]]` live references
- Replaced old `.kiro/scripts/` and `.kiro/steering/` with proper Agent Skill layout
- Updated Cursor and Mastra Code hooks, improved docs/kiro.md
- **Impact:** Brings Kiro IDE support to production quality with native Agent Skill format
- **[@lincolnwan](https://github.com/lincolnwan)** - [PR #80](https://github.com/OthmanAdi/planning-with-files/pull/80)
- Added native GitHub Copilot hooks integration using the early 2026 hooks system
- Created `.github/hooks/planning-with-files.json` with full hook scripts in `.github/hooks/scripts/`
@@ -176,4 +183,4 @@ If you've contributed and don't see your name here, please open an issue! We wan
**Total Contributors:** 25+ and growing!
*Last updated: March 4, 2026*
*Last updated: March 20, 2026*
+7 -4
View File
@@ -42,10 +42,12 @@ See the full list of everyone who made this project better in [CONTRIBUTORS.md](
<details>
<summary><strong>📦 Releases & Session Recovery</strong></summary>
### Current Version: v2.26.0
### Current Version: v2.26.2
| Version | Highlights |
|---------|------------|
| **v2.26.2** | Fix: `---` in hook commands broke YAML frontmatter parsing — hooks now register correctly |
| **v2.26.1** | Fix: session catchup after `/clear` — path sanitization on Windows + content injection (thanks @tony-stark-eth!) |
| **v2.26.0** | IDE audit: Factory hooks, Copilot errorOccurred hook, Gemini hooks, bug fixes |
| **v2.18.2** | Mastra Code hooks fix (hooks.json + docs accuracy) |
| **v2.18.1** | Copilot garbled characters complete fix |
@@ -53,6 +55,7 @@ See the full list of everyone who made this project better in [CONTRIBUTORS.md](
| **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.27.0** | Kiro Agent Skill layout (thanks @EListenX!) |
| **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 |
@@ -98,7 +101,7 @@ These IDEs have dedicated hook configurations that automatically re-read your pl
| GitHub Copilot | [Copilot Setup](docs/copilot.md) | [Hooks](https://docs.github.com/en/copilot/reference/hooks-configuration) (incl. errorOccurred) |
| Mastra Code | [Mastra Setup](docs/mastra.md) | Skills + [Hooks](https://mastra.ai/docs/mastra-code/configuration) |
| Gemini CLI | [Gemini Setup](docs/gemini.md) | Skills + [Hooks](https://geminicli.com/docs/hooks/) |
| Kiro | [Kiro Setup](docs/kiro.md) | [Steering Files](https://kiro.dev/docs/steering/) |
| Kiro | [Kiro Setup](docs/kiro.md) | [Agent Skills](https://kiro.dev/docs/skills/) |
| Codex | [Codex Setup](docs/codex.md) | [Skills + Hooks](https://developers.openai.com/codex/skills) |
| CodeBuddy | [CodeBuddy Setup](docs/codebuddy.md) | [Skills + Hooks](https://www.codebuddy.ai/docs/cli/skills) |
| FactoryAI Droid | [Factory Setup](docs/factory.md) | [Skills + Hooks](https://docs.factory.ai/cli/configuration/skills) |
@@ -143,13 +146,13 @@ A Claude Code plugin that transforms your workflow to use persistent markdown fi
[![Kilocode Skills](https://img.shields.io/badge/Kilocode-Skills-orange)](https://kilo.ai/docs/agent-behavior/skills)
[![Gemini CLI](https://img.shields.io/badge/Gemini%20CLI-Skills-4285F4)](https://geminicli.com/docs/cli/skills/)
[![OpenClaw](https://img.shields.io/badge/OpenClaw-Skills-FF6B6B)](https://openclaw.ai)
[![Kiro](https://img.shields.io/badge/Kiro-Steering-00D4AA)](https://kiro.dev/docs/cli/steering/)
[![Kiro](https://img.shields.io/badge/Kiro-Agent_Skill-00D4AA)](https://kiro.dev/docs/skills/)
[![AdaL CLI](https://img.shields.io/badge/AdaL%20CLI-Skills-9B59B6)](https://docs.sylph.ai/features/plugins-and-skills)
[![Pi Agent](https://img.shields.io/badge/Pi%20Agent-Skills-FF4081)](https://pi.dev)
[![GitHub Copilot](https://img.shields.io/badge/GitHub%20Copilot-Hooks-000000)](https://docs.github.com/en/copilot/reference/hooks-configuration)
[![Mastra Code](https://img.shields.io/badge/Mastra%20Code-Skills-00BCD4)](https://code.mastra.ai)
[![BoxLite](https://img.shields.io/badge/BoxLite-Sandbox-6C3483)](https://boxlite.ai)
[![Version](https://img.shields.io/badge/version-2.26.0-brightgreen)](https://github.com/OthmanAdi/planning-with-files/releases)
[![Version](https://img.shields.io/badge/version-2.26.2-brightgreen)](https://github.com/OthmanAdi/planning-with-files/releases)
[![SkillCheck Validated](https://img.shields.io/badge/SkillCheck-Validated-4c1)](https://getskillcheck.com)
## Quick Install
+68 -81
View File
@@ -1,114 +1,101 @@
# Kiro Setup
# Kiro
How to use planning-with-files with [Kiro](https://kiro.dev).
Use **planning-with-files** with [Kiro](https://kiro.dev): **Agent Skills**, optional **Steering** (created by bootstrap), and on-disk markdown under `.kiro/plan/`.
Official references:
- [Agent Skills](https://kiro.dev/docs/skills/)
- [Steering](https://kiro.dev/docs/steering/) (inclusion modes, `#[[file:path]]` live file references)
---
## Important: Kiro Uses Steering Files
## What ships in this repo
Kiro doesn't use the standard `SKILL.md` format. Instead, it uses **Steering Files** — markdown documents in `.kiro/steering/` that provide persistent project knowledge.
See: [Kiro Steering Docs](https://kiro.dev/docs/cli/steering/)
---
## What This Integration Adds
Only the workspace skill folder:
```
.kiro/
├── steering/
│ ├── planning-workflow.md # Core workflow and quick start
│ ├── planning-rules.md # Critical rules and error protocols
│ └── planning-templates.md # Templates for task_plan, findings, progress
└── scripts/
├── init-session.sh # Initialize planning files (Bash)
├── init-session.ps1 # Initialize planning files (PowerShell)
├── check-complete.sh # Verify phases complete (Bash)
└── check-complete.ps1 # Verify phases complete (PowerShell)
.kiro/skills/planning-with-files/
├── SKILL.md
├── references/ # manus-principles, planning-rules, planning-templates
└── assets/
├── scripts/ # bootstrap, session-catchup, check-complete (.sh + .ps1 + .py)
└── templates/ # task_plan, findings, progress, planning-context (steering)
```
Running **bootstrap** (from the project root) creates:
| Path | Role |
|------|------|
| `.kiro/plan/task_plan.md` | Goal, phases, decisions, errors |
| `.kiro/plan/findings.md` | Research and technical decisions |
| `.kiro/plan/progress.md` | Session log |
| `.kiro/steering/planning-context.md` | `inclusion: auto` + `#[[file:.kiro/plan/…]]` |
Design note: **hooks are not installed by default.** Hooks are workspace-wide. This integration uses the skill, generated steering, and the `[Planning Active]` reminder in `SKILL.md`.
---
## Installation (Workspace)
Copy to your project:
## Install into your project
```bash
git clone https://github.com/OthmanAdi/planning-with-files.git
cp -r planning-with-files/.kiro .kiro
rm -rf planning-with-files
mkdir -p .kiro/skills
cp -r planning-with-files/.kiro/skills/planning-with-files ./.kiro/skills/
```
---
## Installation (Global)
Copy to your global Kiro config:
Then from your **project root**:
```bash
git clone https://github.com/OthmanAdi/planning-with-files.git
mkdir -p ~/.kiro/steering ~/.kiro/scripts
cp planning-with-files/.kiro/steering/* ~/.kiro/steering/
cp planning-with-files/.kiro/scripts/* ~/.kiro/scripts/
rm -rf planning-with-files
sh .kiro/skills/planning-with-files/assets/scripts/bootstrap.sh
```
Global steering applies to all your projects.
Windows (PowerShell):
```powershell
pwsh -ExecutionPolicy Bypass -File .kiro/skills/planning-with-files/assets/scripts/bootstrap.ps1
```
---
## Usage
## Import the skill in Kiro
1. Start Kiro in your project
2. For complex tasks, create the planning files:
1. Open **Agent Steering & Skills** in the Kiro panel.
2. **Import a skill** → local folder → `.kiro/skills/planning-with-files`
3. Or copy that folder to `~/.kiro/skills/planning-with-files` for a **global** skill ([scope](https://kiro.dev/docs/skills/#skill-scope)).
---
## Scripts (under the skill)
All paths are relative to the **project root** after you have copied `.kiro/skills/planning-with-files/` into the project.
| Script | Purpose |
|--------|---------|
| `assets/scripts/bootstrap.sh` / `bootstrap.ps1` | Create `.kiro/plan/*` and `planning-context.md` (idempotent) |
| `assets/scripts/session-catchup.py` | Print mtime + short summary of planning files |
| `assets/scripts/check-complete.sh` / `check-complete.ps1` | Report phase completion vs `.kiro/plan/task_plan.md` |
Examples:
```bash
# Using the init script
bash .kiro/scripts/init-session.sh
# Or manually create:
# - task_plan.md
# - findings.md
# - progress.md
sh .kiro/skills/planning-with-files/assets/scripts/check-complete.sh
$(command -v python3 || command -v python) \
.kiro/skills/planning-with-files/assets/scripts/session-catchup.py "$(pwd)"
```
3. The steering files automatically guide Kiro to:
- Create plans before complex tasks
- Update findings after research
- Log progress and errors
- Follow the 3-strike error protocol
---
## How Steering Works
Kiro loads steering files automatically in every interaction. The planning guidance becomes part of Kiro's project understanding without you needing to explain it each time.
| File | Purpose |
|------|---------|
| `planning-workflow.md` | Core pattern and quick start |
| `planning-rules.md` | Critical rules and error handling |
| `planning-templates.md` | Copy-paste templates |
---
## Helper Scripts
```bash
# Initialize all planning files
bash .kiro/scripts/init-session.sh
# Windows PowerShell
powershell -ExecutionPolicy Bypass -File .kiro/scripts/init-session.ps1
# Verify all phases complete
bash .kiro/scripts/check-complete.sh
```powershell
pwsh -File .kiro/skills/planning-with-files/assets/scripts/check-complete.ps1
python .kiro/skills/planning-with-files/assets/scripts/session-catchup.py (Get-Location)
```
---
## Notes
## Manus-style context engineering
- Steering files are loaded automatically — no manual invocation needed
- Workspace steering (`.kiro/`) takes priority over global (`~/.kiro/`)
- Planning files (`task_plan.md`, etc.) go in your project root, not in `.kiro/`
The skill description and [references/manus-principles.md](../.kiro/skills/planning-with-files/references/manus-principles.md) document the **filesystem-as-memory** pattern discussed in Manus-style agent context engineering.
---
## Template reference
See [references/planning-templates.md](../.kiro/skills/planning-with-files/references/planning-templates.md) for compact paste-friendly skeletons. To use them as **manual steering** in Kiro, copy that file into `.kiro/steering/` and add the YAML front matter described at the top of that file.
+2 -9
View File
@@ -154,15 +154,8 @@ IDE_MANIFESTS = {
include_scripts=False,
),
".kiro": {
# Kiro has a completely different structure (steering files, not SKILL.md)
# Only sync the scripts which live at .kiro/scripts/ (not under skills/)
"scripts/check-complete.sh": ".kiro/scripts/check-complete.sh",
"scripts/check-complete.ps1": ".kiro/scripts/check-complete.ps1",
"scripts/init-session.sh": ".kiro/scripts/init-session.sh",
"scripts/init-session.ps1": ".kiro/scripts/init-session.ps1",
# Steering files are IDE-specific, not synced
},
# Kiro: maintained under .kiro/ (skill + wrappers); not synced from canonical scripts/.
".kiro": {},
}
+2 -2
View File
@@ -7,7 +7,7 @@ hooks:
UserPromptSubmit:
- hooks:
- type: command
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] Active plan detected. If you have not read task_plan.md, progress.md, and findings.md in this conversation, read them now before proceeding.'; fi"
command: "if [ -f task_plan.md ]; then echo '[planning-with-files] ACTIVE PLAN — current state:'; head -50 task_plan.md; echo ''; echo '=== recent progress ==='; tail -20 progress.md 2>/dev/null; echo ''; echo '[planning-with-files] Read findings.md for research context. Continue from the current phase.'; fi"
PreToolUse:
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
hooks:
@@ -23,7 +23,7 @@ hooks:
- type: command
command: "SD=\"${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/planning-with-files}/scripts\"; powershell.exe -NoProfile -ExecutionPolicy Bypass -File \"$SD/check-complete.ps1\" 2>/dev/null || sh \"$SD/check-complete.sh\""
metadata:
version: "2.23.0"
version: "2.26.1"
---
# Planning with Files
@@ -17,12 +17,42 @@ from typing import List, Dict, Optional, Tuple
PLANNING_FILES = ['task_plan.md', 'progress.md', 'findings.md']
def normalize_path(project_path: str) -> str:
"""Normalize project path to match Claude Code's internal representation.
Claude Code stores session directories using the Windows-native path
(e.g., C:\\Users\\...) sanitized with separators replaced by dashes.
Git Bash passes /c/Users/... which produces a DIFFERENT sanitized
string. This function converts Git Bash paths to Windows paths first.
"""
p = project_path
# Git Bash / MSYS2: /c/Users/... -> C:/Users/...
if len(p) >= 3 and p[0] == '/' and p[2] == '/':
p = p[1].upper() + ':' + p[2:]
# Resolve to absolute path to handle relative paths and symlinks
try:
resolved = str(Path(p).resolve())
# On Windows, resolve() returns C:\Users\... which is what we want
if os.name == 'nt' or '\\' in resolved:
p = resolved
except (OSError, ValueError):
pass
return p
def get_project_dir(project_path: str) -> Tuple[Optional[Path], Optional[str]]:
"""Resolve session storage path for the current runtime variant."""
sanitized = project_path.replace('/', '-')
if not sanitized.startswith('-'):
sanitized = '-' + sanitized
normalized = normalize_path(project_path)
# Claude Code's sanitization: replace path separators and : with -
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
# Strip leading dash if present (Unix absolute paths start with /)
if sanitized.startswith('-'):
sanitized = sanitized[1:]
claude_path = Path.home() / '.claude' / 'projects' / sanitized
@@ -50,7 +80,7 @@ def get_sessions_sorted(project_dir: Path) -> List[Path]:
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:
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
+230
View File
@@ -0,0 +1,230 @@
#!/bin/bash
# test_clear_recovery.sh — Automated test for session recovery after /clear
#
# Tests that the UserPromptSubmit hook injects actual plan content
# (not just advisory text) when task_plan.md exists.
#
# This simulates what happens after /clear:
# 1. Context is empty
# 2. User sends a message
# 3. UserPromptSubmit hook fires
# 4. Hook output is injected into context
#
# PASS = hook output contains actual plan content
# FAIL = hook output is just advisory text or empty
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
TESTDIR=$(mktemp -d)
PASS=0
FAIL=0
cleanup() {
rm -rf "$TESTDIR"
echo ""
if [ "$FAIL" -eq 0 ]; then
echo "========================================="
echo " ALL $PASS TESTS PASSED"
echo "========================================="
else
echo "========================================="
echo " $FAIL FAILED, $PASS PASSED"
echo "========================================="
exit 1
fi
}
trap cleanup EXIT
echo "=== Session Recovery Hook Test ==="
echo "Test dir: $TESTDIR"
echo ""
# --- Setup: Create realistic planning files ---
cat > "$TESTDIR/task_plan.md" << 'PLAN'
# Task Plan
## Goal
Build a REST API with authentication, database, and tests
## Current Phase
Phase 2: Database Integration - in_progress
## Phases
### Phase 1: Project Setup
**Status:** complete
- [x] Initialize Node.js project
- [x] Install dependencies
### Phase 2: Database Integration
**Status:** in_progress
- [x] Set up PostgreSQL connection
- [ ] Create user schema
- [ ] Add migration scripts
### Phase 3: Authentication
**Status:** pending
- [ ] JWT token generation
- [ ] Login/register endpoints
## Errors Encountered
| Error | Attempt | Resolution |
|-------|---------|------------|
| pg connection refused | 1 | Started docker container |
PLAN
cat > "$TESTDIR/progress.md" << 'PROGRESS'
# Progress Log
## Session: 2026-03-20
**Phase:** Phase 2: Database Integration
### Actions Taken
1. Created database connection module
2. Tested connection to PostgreSQL
3. Fixed docker networking issue
4. Started work on user schema
### Files Modified
- `src/db/connection.ts` — Database pool setup
- `docker-compose.yml` — Added PostgreSQL service
PROGRESS
cat > "$TESTDIR/findings.md" << 'FINDINGS'
# Findings
## Technical Decisions
| Decision | Chosen | Why |
|----------|--------|-----|
| ORM | Drizzle | Type-safe, lightweight |
| Auth | JWT | Stateless, simple |
FINDINGS
# --- Test 1: Hook injects plan content (not just advisory) ---
echo "Test 1: UserPromptSubmit hook injects plan content"
cd "$TESTDIR"
OUTPUT=$(bash -c 'if [ -f task_plan.md ]; then echo "[planning-with-files] ACTIVE PLAN — current state:"; head -50 task_plan.md; echo ""; echo "=== recent progress ==="; tail -20 progress.md 2>/dev/null; echo ""; echo "[planning-with-files] Read findings.md for research context. Continue from the current phase."; fi' 2>/dev/null)
if echo "$OUTPUT" | grep -q "Build a REST API"; then
echo " PASS: Hook output contains the goal"
PASS=$((PASS + 1))
else
echo " FAIL: Hook output missing the goal"
FAIL=$((FAIL + 1))
fi
if echo "$OUTPUT" | grep -q "Phase 2.*in_progress"; then
echo " PASS: Hook output contains current phase status"
PASS=$((PASS + 1))
else
echo " FAIL: Hook output missing current phase"
FAIL=$((FAIL + 1))
fi
if echo "$OUTPUT" | grep -q "Database Integration"; then
echo " PASS: Hook output contains phase name"
PASS=$((PASS + 1))
else
echo " FAIL: Hook output missing phase name"
FAIL=$((FAIL + 1))
fi
if echo "$OUTPUT" | grep -q "Created database connection module"; then
echo " PASS: Hook output contains recent progress"
PASS=$((PASS + 1))
else
echo " FAIL: Hook output missing recent progress"
FAIL=$((FAIL + 1))
fi
if echo "$OUTPUT" | grep -q "ACTIVE PLAN"; then
echo " PASS: Hook output has clear ACTIVE PLAN header"
PASS=$((PASS + 1))
else
echo " FAIL: Hook output missing ACTIVE PLAN header"
FAIL=$((FAIL + 1))
fi
echo ""
# --- Test 2: Hook is silent when no plan exists ---
echo "Test 2: Hook is silent when no task_plan.md"
cd /tmp
OUTPUT2=$(bash -c 'if [ -f task_plan.md ]; then echo "[planning-with-files] ACTIVE PLAN — current state:"; head -50 task_plan.md; fi' 2>/dev/null)
if [ -z "$OUTPUT2" ]; then
echo " PASS: No output when no plan file"
PASS=$((PASS + 1))
else
echo " FAIL: Hook produced output without plan file"
FAIL=$((FAIL + 1))
fi
echo ""
# --- Test 3: Session catchup path fix (Windows Git Bash paths) ---
echo "Test 3: Session catchup path sanitization"
SCRIPT="${REPO_ROOT}/skills/planning-with-files/scripts/session-catchup.py"
PYTHON=$(command -v python3 || command -v python)
if [ -f "$SCRIPT" ]; then
# Test that normalize_path handles Git Bash /c/ conversion
if grep -q "p\[1\].upper() + ':'" "$SCRIPT"; then
echo " PASS: normalize_path converts /c/ to C: (drive letter conversion present)"
PASS=$((PASS + 1))
else
echo " FAIL: normalize_path missing Git Bash drive letter conversion"
FAIL=$((FAIL + 1))
fi
# Test UTF-8 encoding parameter
if grep -q "encoding='utf-8'" "$SCRIPT"; then
echo " PASS: session file opened with UTF-8 encoding"
PASS=$((PASS + 1))
else
echo " FAIL: session file not opened with UTF-8 encoding"
FAIL=$((FAIL + 1))
fi
# Test that both \ and / are replaced in sanitization
if grep -q "replace('\\\\\\\\', '-')" "$SCRIPT" && grep -q "replace('/', '-')" "$SCRIPT"; then
echo " PASS: sanitization handles both \\ and / separators"
PASS=$((PASS + 1))
else
echo " FAIL: sanitization missing separator handling"
FAIL=$((FAIL + 1))
fi
else
echo " SKIP: session-catchup.py not found at $SCRIPT"
fi
echo ""
# --- Test 4: PreToolUse hook still injects plan header ---
echo "Test 4: PreToolUse hook injects plan header"
cd "$TESTDIR"
OUTPUT3=$(bash -c 'cat task_plan.md 2>/dev/null | head -30 || true' 2>/dev/null)
if echo "$OUTPUT3" | grep -q "Task Plan"; then
echo " PASS: PreToolUse outputs plan header"
PASS=$((PASS + 1))
else
echo " FAIL: PreToolUse did not output plan"
FAIL=$((FAIL + 1))
fi
echo ""
# --- Test 5: PostToolUse reminder mentions progress.md ---
echo "Test 5: PostToolUse mentions progress.md"
OUTPUT4=$(bash -c 'if [ -f task_plan.md ]; then echo "[planning-with-files] Update progress.md with what you just did. If a phase is now complete, update task_plan.md status."; fi' 2>/dev/null)
if echo "$OUTPUT4" | grep -q "progress.md"; then
echo " PASS: PostToolUse mentions progress.md"
PASS=$((PASS + 1))
else
echo " FAIL: PostToolUse does not mention progress.md"
FAIL=$((FAIL + 1))
fi
+59
View File
@@ -0,0 +1,59 @@
"""Test the path sanitization fix for session-catchup.py"""
import os
import sys
from pathlib import Path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'skills', 'planning-with-files', 'scripts'))
# Re-implement the fix here for testing (avoids import issues)
def normalize_path(project_path):
p = project_path
# Git Bash / MSYS2: /c/Users/... -> C:/Users/...
if len(p) >= 3 and p[0] == '/' and p[2] == '/':
p = p[1].upper() + ':' + p[2:]
try:
resolved = str(Path(p).resolve())
if os.name == 'nt' or os.sep == '\\':
p = resolved
except (OSError, ValueError):
pass
return p
def sanitize(project_path):
normalized = normalize_path(project_path)
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
if sanitized.startswith('-'):
sanitized = sanitized[1:]
return sanitized
expected = "C--Users-oasrvadmin-Documents-planning-with-files-repo"
tests = {
"Git Bash": "/c/Users/oasrvadmin/Documents/planning-with-files-repo",
"Forward slash": "C:/Users/oasrvadmin/Documents/planning-with-files-repo",
}
all_pass = True
for label, path in tests.items():
result = sanitize(path)
claude_dir = Path.home() / '.claude' / 'projects' / result
match = result == expected
exists = claude_dir.exists()
print(f"[{label}]")
print(f" Input: {path}")
print(f" Result: {result}")
print(f" Expected: {expected}")
print(f" Match: {match}")
print(f" Dir exists: {exists}")
print()
if not match:
all_pass = False
if all_pass:
print("ALL TESTS PASSED")
else:
print("SOME TESTS FAILED")
sys.exit(1)