Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c84f56574e | ||
|
|
4f2586691a | ||
|
|
1844bbb90f | ||
|
|
ab10960a4b | ||
|
|
8ee4328ef8 | ||
|
|
ce59730881 | ||
|
|
74d37d96ff | ||
|
|
69ded714b7 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "planning-with-files",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"description": "Manus-style persistent markdown files for planning, progress tracking, and knowledge storage. Includes hooks for automatic plan re-reading and completion verification. Use when starting complex tasks, multi-step projects, research tasks, or when you want structured output.",
|
||||
"author": {
|
||||
"name": "OthmanAdi",
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# Installing planning-with-files for Codex
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Codex IDE installed
|
||||
- Git installed (optional, for cloning)
|
||||
|
||||
## Installation
|
||||
|
||||
### Option 1: Clone Repository (Recommended)
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.codex/skills
|
||||
cd ~/.codex/skills
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
```
|
||||
|
||||
### Option 2: Manual Copy
|
||||
|
||||
1. Download or clone this repository
|
||||
2. Copy the entire `planning-with-files/` directory to `~/.codex/skills/`
|
||||
3. Ensure the structure matches:
|
||||
```
|
||||
~/.codex/skills/planning-with-files/
|
||||
├── planning-with-files/
|
||||
│ ├── SKILL.md
|
||||
│ ├── templates/
|
||||
│ └── scripts/
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### If Using Superpowers
|
||||
|
||||
If you have [obra/superpowers](https://github.com/obra/superpowers) installed:
|
||||
|
||||
```bash
|
||||
~/.codex/superpowers/.codex/superpowers-codex use-skill planning-with-files
|
||||
```
|
||||
|
||||
Superpowers will find it in your personal skills directory.
|
||||
|
||||
### If NOT Using Superpowers
|
||||
|
||||
Manually read the skill file when starting complex tasks:
|
||||
|
||||
```bash
|
||||
cat ~/.codex/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
Or add to your `~/.codex/AGENTS.md`:
|
||||
|
||||
```markdown
|
||||
## Planning with Files
|
||||
|
||||
<IMPORTANT>
|
||||
For complex multi-step tasks (3+ steps, research, building projects):
|
||||
1. Read the planning-with-files skill: `cat ~/.codex/skills/planning-with-files/planning-with-files/SKILL.md`
|
||||
2. Create task_plan.md, findings.md, progress.md in your project directory
|
||||
3. Follow the 3-file pattern throughout the task
|
||||
</IMPORTANT>
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Check that the skill exists:
|
||||
|
||||
```bash
|
||||
ls -la ~/.codex/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill not found
|
||||
|
||||
- Verify path: `~/.codex/skills/planning-with-files/planning-with-files/SKILL.md`
|
||||
- Check file exists and is readable
|
||||
- Ensure SKILL.md has proper YAML frontmatter
|
||||
|
||||
### Scripts not executing
|
||||
|
||||
**Windows users:**
|
||||
- Use PowerShell versions: `*.ps1`
|
||||
- Set execution policy: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
|
||||
|
||||
**Unix/Mac users:**
|
||||
- Make scripts executable: `chmod +x ~/.codex/skills/planning-with-files/scripts/*.sh`
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Issues: https://github.com/OthmanAdi/planning-with-files/issues
|
||||
- Documentation: https://github.com/OthmanAdi/planning-with-files
|
||||
@@ -0,0 +1,139 @@
|
||||
# Installing planning-with-files for OpenCode
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- OpenCode.ai installed
|
||||
- Git installed (optional, for cloning)
|
||||
|
||||
## Installation
|
||||
|
||||
### Option 1: Global Installation (All Projects)
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/skills
|
||||
cd ~/.config/opencode/skills
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
```
|
||||
|
||||
### Option 2: Project-Specific Installation
|
||||
|
||||
```bash
|
||||
# In your OpenCode project root
|
||||
mkdir -p .opencode/skills
|
||||
cd .opencode/skills
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
```
|
||||
|
||||
### Option 3: Manual Copy
|
||||
|
||||
**For global installation:**
|
||||
1. Download or clone this repository
|
||||
2. Copy to `~/.config/opencode/skills/planning-with-files/`
|
||||
|
||||
**For project installation:**
|
||||
1. Download or clone this repository
|
||||
2. Copy to `.opencode/skills/planning-with-files/` in your project
|
||||
|
||||
## File Structure
|
||||
|
||||
After installation:
|
||||
|
||||
```
|
||||
~/.config/opencode/skills/planning-with-files/ (or .opencode/skills/planning-with-files/)
|
||||
├── planning-with-files/
|
||||
│ ├── SKILL.md # Main skill file
|
||||
│ ├── templates/
|
||||
│ │ ├── task_plan.md
|
||||
│ │ ├── findings.md
|
||||
│ │ └── progress.md
|
||||
│ └── scripts/
|
||||
│ ├── check-complete.sh
|
||||
│ ├── check-complete.ps1
|
||||
│ ├── init-session.sh
|
||||
│ ├── init-session.ps1
|
||||
│ └── session-catchup.py
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### If Using Superpowers Plugin
|
||||
|
||||
If you have [obra/superpowers](https://github.com/obra/superpowers) installed as an OpenCode plugin:
|
||||
|
||||
```
|
||||
Use the use_skill tool with skill_name: "planning-with-files"
|
||||
```
|
||||
|
||||
OpenCode will find it automatically (personal skills override superpowers skills).
|
||||
|
||||
### If NOT Using Superpowers
|
||||
|
||||
You can still manually load the skill:
|
||||
|
||||
1. Navigate to `~/.config/opencode/skills/planning-with-files/planning-with-files/`
|
||||
2. Read SKILL.md
|
||||
3. Follow the instructions for creating task_plan.md, findings.md, progress.md
|
||||
|
||||
Or create a custom tool/command to load it.
|
||||
|
||||
## Skill Priority
|
||||
|
||||
If installed as:
|
||||
- **Project skill** (`.opencode/skills/planning-with-files/`) - Highest priority
|
||||
- **Personal skill** (`~/.config/opencode/skills/planning-with-files/`) - Medium priority
|
||||
- If superpowers has a planning-with-files skill - Lowest priority
|
||||
|
||||
Project skills override personal skills, which override superpowers skills.
|
||||
|
||||
## Verification
|
||||
|
||||
**Global installation:**
|
||||
```bash
|
||||
ls -la ~/.config/opencode/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
**Project installation:**
|
||||
```bash
|
||||
ls -la .opencode/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill not loading
|
||||
|
||||
1. Verify SKILL.md exists at the correct path
|
||||
2. Check YAML frontmatter is valid:
|
||||
```yaml
|
||||
---
|
||||
name: planning-with-files
|
||||
description: ...
|
||||
---
|
||||
```
|
||||
3. If using superpowers plugin, use `find_skills` tool to verify it's discovered
|
||||
|
||||
### Scripts not executing
|
||||
|
||||
**Windows:**
|
||||
- Use PowerShell versions: `*.ps1`
|
||||
- Set execution policy: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
|
||||
|
||||
**Unix/Mac:**
|
||||
- Make executable: `chmod +x ~/.config/opencode/skills/planning-with-files/scripts/*.sh`
|
||||
|
||||
### oh-my-opencode Blocking
|
||||
|
||||
If using oh-my-opencode and the skill isn't recognized:
|
||||
|
||||
1. Check `~/.config/opencode/oh-my-opencode.json`
|
||||
2. Ensure planning-with-files is NOT in `disabled_skills` array:
|
||||
```json
|
||||
{
|
||||
"disabled_skills": []
|
||||
}
|
||||
```
|
||||
3. Restart OpenCode
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Issues: https://github.com/OthmanAdi/planning-with-files/issues
|
||||
- Documentation: https://github.com/OthmanAdi/planning-with-files
|
||||
+105
-5
@@ -2,6 +2,111 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [2.3.0] - 2026-01-17
|
||||
|
||||
### Added
|
||||
|
||||
- **Codex IDE Support**
|
||||
- Created `.codex/INSTALL.md` with installation instructions
|
||||
- Skills install to `~/.codex/skills/planning-with-files/`
|
||||
- Works with obra/superpowers or standalone
|
||||
- Added `docs/codex.md` for user documentation
|
||||
- Based on analysis of obra/superpowers Codex implementation
|
||||
|
||||
- **OpenCode IDE Support** (Issue #27)
|
||||
- Created `.opencode/INSTALL.md` with installation instructions
|
||||
- Global installation: `~/.config/opencode/skills/planning-with-files/`
|
||||
- Project installation: `.opencode/skills/planning-with-files/`
|
||||
- Works with obra/superpowers plugin or standalone
|
||||
- oh-my-opencode compatibility documented
|
||||
- Added `docs/opencode.md` for user documentation
|
||||
- Based on analysis of obra/superpowers OpenCode plugin
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated README.md with Supported IDEs table
|
||||
- Updated README.md file structure diagram
|
||||
- Updated docs/installation.md with Codex and OpenCode sections
|
||||
- Version bump to 2.3.0
|
||||
|
||||
### Documentation
|
||||
|
||||
- Added Codex and OpenCode to IDE support table in README
|
||||
- Created comprehensive installation guides for both IDEs
|
||||
- Documented skill priority system for OpenCode
|
||||
- Documented integration with superpowers ecosystem
|
||||
|
||||
### Research
|
||||
|
||||
This implementation is based on real analysis of:
|
||||
- [obra/superpowers](https://github.com/obra/superpowers) repository
|
||||
- Codex skill system and CLI architecture
|
||||
- OpenCode plugin system and skill resolution
|
||||
- Skill priority and override mechanisms
|
||||
|
||||
### Thanks
|
||||
|
||||
- @Realtyxxx for feedback on Issue #27 about OpenCode support
|
||||
- obra for the superpowers reference implementation
|
||||
|
||||
---
|
||||
|
||||
## [2.2.2] - 2026-01-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Restored Skill Activation Language** (PR #34)
|
||||
- Restored the activation trigger in SKILL.md description
|
||||
- Description now includes: "Use when starting complex multi-step tasks, research projects, or any task requiring >5 tool calls"
|
||||
- This language was accidentally removed during the v2.2.1 merge
|
||||
- Helps Claude auto-activate the skill when detecting appropriate tasks
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated version to 2.2.2 in all SKILL.md files and plugin.json
|
||||
|
||||
### Thanks
|
||||
|
||||
- Community members for catching this issue
|
||||
|
||||
---
|
||||
|
||||
## [2.2.1] - 2026-01-17
|
||||
|
||||
### Added
|
||||
|
||||
- **Session Recovery Feature** (PR #33 by @lasmarois)
|
||||
- Automatically detect and recover unsynced work from previous sessions after `/clear`
|
||||
- New `scripts/session-catchup.py` analyzes previous session JSONL files
|
||||
- Finds last planning file update and extracts conversation that happened after
|
||||
- Recovery triggered automatically when invoking `/planning-with-files`
|
||||
- Pure Python stdlib implementation, no external dependencies
|
||||
|
||||
- **PreToolUse Hook Enhancement**
|
||||
- Now triggers on Read/Glob/Grep in addition to Write/Edit/Bash
|
||||
- Keeps task_plan.md in attention during research/exploration phases
|
||||
- Better context management throughout workflow
|
||||
|
||||
### Changed
|
||||
|
||||
- SKILL.md restructured with session recovery as first instruction
|
||||
- Description updated to mention session recovery feature
|
||||
- README updated with session recovery workflow and instructions
|
||||
|
||||
### Documentation
|
||||
|
||||
- Added "Session Recovery" section to README
|
||||
- Documented optimal workflow for context window management
|
||||
- Instructions for disabling auto-compact in Claude Code settings
|
||||
|
||||
### Thanks
|
||||
|
||||
Special thanks to:
|
||||
- @lasmarois for session recovery implementation (PR #33)
|
||||
- Community members for testing and feedback
|
||||
|
||||
---
|
||||
|
||||
## [2.2.0] - 2026-01-17
|
||||
|
||||
### Added
|
||||
@@ -76,11 +181,6 @@ Special thanks to:
|
||||
- @mtuwei for reporting Windows compatibility issues (#32)
|
||||
- All community members who tested and provided feedback
|
||||
|
||||
## [2.1.2] - 2026-01-11
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Template Files Not Found in Cache** (Fixes #18)
|
||||
- Root cause: `${CLAUDE_PLUGIN_ROOT}` resolves to repo root, but templates were only in subfolders
|
||||
- Added `templates/` and `scripts/` directories at repo root level
|
||||
- Now templates are accessible regardless of how `CLAUDE_PLUGIN_ROOT` resolves
|
||||
|
||||
@@ -25,6 +25,13 @@ These amazing people have contributed code, documentation, or significant improv
|
||||
- Created workflow diagram showing task lifecycle
|
||||
- **Impact:** Dramatically improved beginner onboarding
|
||||
|
||||
- **[@lasmarois](https://github.com/lasmarois)** - [PR #33](https://github.com/OthmanAdi/planning-with-files/pull/33)
|
||||
- Created session recovery feature for context preservation after `/clear`
|
||||
- Built `session-catchup.py` script to analyze previous session JSONL files
|
||||
- Enhanced PreToolUse hook to include Read/Glob/Grep operations
|
||||
- Restructured SKILL.md for better session recovery workflow
|
||||
- **Impact:** Solves context loss problem, enables seamless work resumption
|
||||
|
||||
- **[@aimasteracc](https://github.com/aimasteracc)** - [PR #30](https://github.com/OthmanAdi/planning-with-files/pull/30)
|
||||
- Added Kilocode IDE support and documentation
|
||||
- Created PowerShell scripts for Windows compatibility
|
||||
|
||||
@@ -16,7 +16,7 @@ A Claude Code plugin that transforms your workflow to use persistent markdown fi
|
||||
[](https://code.claude.com/docs/en/plugins)
|
||||
[](https://code.claude.com/docs/en/skills)
|
||||
[](https://docs.cursor.com/context/rules-for-ai)
|
||||
[](https://github.com/OthmanAdi/planning-with-files/releases)
|
||||
[](https://github.com/OthmanAdi/planning-with-files/releases)
|
||||
|
||||
## Quick Install
|
||||
|
||||
@@ -27,6 +27,16 @@ A Claude Code plugin that transforms your workflow to use persistent markdown fi
|
||||
|
||||
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 |
|
||||
| Cursor | ✅ Full Support | [Cursor Setup](docs/cursor.md) | Rules |
|
||||
| Kilocode | ✅ Full Support | [Kilocode Setup](docs/kilocode.md) | Rules |
|
||||
| OpenCode | ✅ Full Support | [OpenCode Setup](docs/opencode.md) | Personal/Project Skill |
|
||||
| Codex | ✅ Full Support | [Codex Setup](docs/codex.md) | Personal Skill |
|
||||
|
||||
## Documentation
|
||||
|
||||
| Document | Description |
|
||||
@@ -38,15 +48,19 @@ See [docs/installation.md](docs/installation.md) for all installation methods.
|
||||
| [Cursor Setup](docs/cursor.md) | Cursor IDE-specific instructions |
|
||||
| [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 |
|
||||
|
||||
## Versions
|
||||
|
||||
| Version | Features | Install |
|
||||
|---------|----------|---------|
|
||||
| **v2.2.0** (current) | Kilo Code IDE support, Windows PowerShell support, OS-aware hooks | `/plugin install planning-with-files@planning-with-files` |
|
||||
| **v2.3.0** (current) | Codex & OpenCode IDE support | `/plugin install planning-with-files@planning-with-files` |
|
||||
| **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.1** | Fix plugin template paths | See [releases](https://github.com/OthmanAdi/planning-with-files/releases) |
|
||||
| **v2.1.0** | Claude Code v2.1 compatible, SessionStart hook, PostToolUse hook, user-invocable | 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` |
|
||||
|
||||
@@ -102,6 +116,45 @@ Or invoke manually with `/planning-with-files`.
|
||||
|
||||
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`
|
||||
@@ -122,7 +175,9 @@ planning-with-files/
|
||||
│ ├── troubleshooting.md
|
||||
│ ├── cursor.md
|
||||
│ ├── windows.md
|
||||
│ └── kilocode.md
|
||||
│ ├── kilocode.md
|
||||
│ ├── codex.md
|
||||
│ └── opencode.md
|
||||
├── planning-with-files/ # Plugin skill folder
|
||||
│ ├── SKILL.md
|
||||
│ ├── templates/
|
||||
@@ -138,6 +193,10 @@ planning-with-files/
|
||||
│ ├── check-complete.sh
|
||||
│ ├── init-session.ps1 # Windows PowerShell
|
||||
│ └── check-complete.ps1 # Windows PowerShell
|
||||
├── .codex/ # Codex IDE installation guide
|
||||
│ └── INSTALL.md
|
||||
├── .opencode/ # OpenCode IDE installation guide
|
||||
│ └── INSTALL.md
|
||||
├── .claude-plugin/ # Plugin manifest
|
||||
├── .cursor/ # Cursor rules
|
||||
├── .kilocode/ # Kilo Code rules
|
||||
@@ -185,6 +244,7 @@ See [docs/kilocode.md](docs/kilocode.md) for detailed Kilo Code integration guid
|
||||
|
||||
| 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!*
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Codex IDE Support
|
||||
|
||||
## Overview
|
||||
|
||||
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.
|
||||
|
||||
### Quick Install
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.codex/skills
|
||||
cd ~/.codex/skills
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
```
|
||||
|
||||
## Usage with Superpowers
|
||||
|
||||
If you have [obra/superpowers](https://github.com/obra/superpowers) installed:
|
||||
|
||||
```bash
|
||||
~/.codex/superpowers/.codex/superpowers-codex use-skill planning-with-files
|
||||
```
|
||||
|
||||
## Usage without Superpowers
|
||||
|
||||
Add to your `~/.codex/AGENTS.md`:
|
||||
|
||||
```markdown
|
||||
## Planning with Files
|
||||
|
||||
<IMPORTANT>
|
||||
For complex tasks (3+ steps, research, projects):
|
||||
1. Read skill: `cat ~/.codex/skills/planning-with-files/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>
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
ls -la ~/.codex/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
## Learn More
|
||||
|
||||
- [Installation Guide](installation.md)
|
||||
- [Quick Start](quickstart.md)
|
||||
- [Workflow Diagram](workflow.md)
|
||||
@@ -153,6 +153,14 @@ See [docs/windows.md](windows.md) for Windows-specific installation notes.
|
||||
|
||||
See [docs/cursor.md](cursor.md) for Cursor IDE installation.
|
||||
|
||||
### Codex
|
||||
|
||||
See [docs/codex.md](codex.md) for Codex IDE installation.
|
||||
|
||||
### OpenCode
|
||||
|
||||
See [docs/opencode.md](opencode.md) for OpenCode IDE installation.
|
||||
|
||||
---
|
||||
|
||||
## Need Help?
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# OpenCode IDE Support
|
||||
|
||||
## Overview
|
||||
|
||||
planning-with-files works with OpenCode as a personal or project skill.
|
||||
|
||||
## Installation
|
||||
|
||||
See [.opencode/INSTALL.md](../.opencode/INSTALL.md) for detailed installation instructions.
|
||||
|
||||
### Quick Install (Global)
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/skills
|
||||
cd ~/.config/opencode/skills
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
```
|
||||
|
||||
### Quick Install (Project)
|
||||
|
||||
```bash
|
||||
mkdir -p .opencode/skills
|
||||
cd .opencode/skills
|
||||
git clone https://github.com/OthmanAdi/planning-with-files.git
|
||||
```
|
||||
|
||||
## Usage with Superpowers Plugin
|
||||
|
||||
If you have [obra/superpowers](https://github.com/obra/superpowers) OpenCode plugin:
|
||||
|
||||
```
|
||||
Use the use_skill tool with skill_name: "planning-with-files"
|
||||
```
|
||||
|
||||
## Usage without Superpowers
|
||||
|
||||
Manually read the skill file when starting complex tasks:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
**~/.config/opencode/oh-my-opencode.json:**
|
||||
```json
|
||||
{
|
||||
"disabled_skills": []
|
||||
}
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
**Global:**
|
||||
```bash
|
||||
ls -la ~/.config/opencode/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
**Project:**
|
||||
```bash
|
||||
ls -la .opencode/skills/planning-with-files/planning-with-files/SKILL.md
|
||||
```
|
||||
|
||||
## Learn More
|
||||
|
||||
- [Installation Guide](installation.md)
|
||||
- [Quick Start](quickstart.md)
|
||||
- [Workflow Diagram](workflow.md)
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.2.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.
|
||||
version: "2.3.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.
|
||||
user-invocable: true
|
||||
allowed-tools:
|
||||
- Read
|
||||
@@ -13,12 +13,8 @@ allowed-tools:
|
||||
- WebFetch
|
||||
- WebSearch
|
||||
hooks:
|
||||
SessionStart:
|
||||
- hooks:
|
||||
- type: command
|
||||
command: "echo '[planning-with-files] Ready. Auto-activates for complex tasks, or invoke manually with /planning-with-files'"
|
||||
PreToolUse:
|
||||
- matcher: "Write|Edit|Bash"
|
||||
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
|
||||
hooks:
|
||||
- type: command
|
||||
command: "cat task_plan.md 2>/dev/null | head -30 || true"
|
||||
@@ -42,31 +38,41 @@ hooks:
|
||||
|
||||
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
|
||||
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/session-catchup.py "$(pwd)"
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
When using this skill:
|
||||
|
||||
- **Templates** are stored in the skill directory at `${CLAUDE_PLUGIN_ROOT}/templates/`
|
||||
- **Your planning files** (`task_plan.md`, `findings.md`, `progress.md`) should be created in **your project directory** — the folder where you're working
|
||||
- **Templates** are in `${CLAUDE_PLUGIN_ROOT}/templates/`
|
||||
- **Your planning files** go in **your project directory**
|
||||
|
||||
| Location | What Goes There |
|
||||
|----------|-----------------|
|
||||
| Skill directory (`${CLAUDE_PLUGIN_ROOT}/`) | Templates, scripts, reference docs |
|
||||
| Your project directory | `task_plan.md`, `findings.md`, `progress.md` |
|
||||
|
||||
This ensures your planning files live alongside your code, not buried in the skill installation folder.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Before ANY complex task:
|
||||
|
||||
1. **Create `task_plan.md`** in your project — Use [templates/task_plan.md](templates/task_plan.md) as reference
|
||||
2. **Create `findings.md`** in your project — Use [templates/findings.md](templates/findings.md) as reference
|
||||
3. **Create `progress.md`** in your project — Use [templates/progress.md](templates/progress.md) as reference
|
||||
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:** All three planning files should be created in your current working directory (your project root), not in the skill's installation folder.
|
||||
> **Note:** Planning files go in your project root, not the skill installation folder.
|
||||
|
||||
## The Core Pattern
|
||||
|
||||
@@ -197,6 +203,7 @@ 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
|
||||
|
||||
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
#!/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 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)
|
||||
|
||||
# Only output if there's unsynced content
|
||||
if last_update_line < 0:
|
||||
messages_after = extract_messages_after(messages, len(messages) - 30)
|
||||
else:
|
||||
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("\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()
|
||||
Executable
+208
@@ -0,0 +1,208 @@
|
||||
#!/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 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)
|
||||
|
||||
# Only output if there's unsynced content
|
||||
if last_update_line < 0:
|
||||
messages_after = extract_messages_after(messages, len(messages) - 30)
|
||||
else:
|
||||
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("\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()
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
version: "2.2.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.
|
||||
version: "2.3.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.
|
||||
user-invocable: true
|
||||
allowed-tools:
|
||||
- Read
|
||||
@@ -13,12 +13,8 @@ allowed-tools:
|
||||
- WebFetch
|
||||
- WebSearch
|
||||
hooks:
|
||||
SessionStart:
|
||||
- hooks:
|
||||
- type: command
|
||||
command: "echo '[planning-with-files] Ready. Auto-activates for complex tasks, or invoke manually with /planning-with-files'"
|
||||
PreToolUse:
|
||||
- matcher: "Write|Edit|Bash"
|
||||
- matcher: "Write|Edit|Bash|Read|Glob|Grep"
|
||||
hooks:
|
||||
- type: command
|
||||
command: "cat task_plan.md 2>/dev/null | head -30 || true"
|
||||
@@ -42,31 +38,41 @@ hooks:
|
||||
|
||||
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
|
||||
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/session-catchup.py "$(pwd)"
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
When using this skill:
|
||||
|
||||
- **Templates** are stored in the skill directory at `${CLAUDE_PLUGIN_ROOT}/templates/`
|
||||
- **Your planning files** (`task_plan.md`, `findings.md`, `progress.md`) should be created in **your project directory** — the folder where you're working
|
||||
- **Templates** are in `${CLAUDE_PLUGIN_ROOT}/templates/`
|
||||
- **Your planning files** go in **your project directory**
|
||||
|
||||
| Location | What Goes There |
|
||||
|----------|-----------------|
|
||||
| Skill directory (`${CLAUDE_PLUGIN_ROOT}/`) | Templates, scripts, reference docs |
|
||||
| Your project directory | `task_plan.md`, `findings.md`, `progress.md` |
|
||||
|
||||
This ensures your planning files live alongside your code, not buried in the skill installation folder.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Before ANY complex task:
|
||||
|
||||
1. **Create `task_plan.md`** in your project — Use [templates/task_plan.md](templates/task_plan.md) as reference
|
||||
2. **Create `findings.md`** in your project — Use [templates/findings.md](templates/findings.md) as reference
|
||||
3. **Create `progress.md`** in your project — Use [templates/progress.md](templates/progress.md) as reference
|
||||
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:** All three planning files should be created in your current working directory (your project root), not in the skill's installation folder.
|
||||
> **Note:** Planning files go in your project root, not the skill installation folder.
|
||||
|
||||
## The Core Pattern
|
||||
|
||||
@@ -197,6 +203,7 @@ 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
|
||||
|
||||
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
#!/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 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)
|
||||
|
||||
# Only output if there's unsynced content
|
||||
if last_update_line < 0:
|
||||
messages_after = extract_messages_after(messages, len(messages) - 30)
|
||||
else:
|
||||
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("\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()
|
||||
Reference in New Issue
Block a user