planager 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- planager/__init__.py +1 -0
- planager/cli.py +112 -0
- planager/templates/CLAUDE.md.snippet +75 -0
- planager/templates/__init__.py +0 -0
- planager/templates/plan/SKILL.md +35 -0
- planager/templates/plan-status/SKILL.md +22 -0
- planager-0.1.1.dist-info/METADATA +115 -0
- planager-0.1.1.dist-info/RECORD +10 -0
- planager-0.1.1.dist-info/WHEEL +4 -0
- planager-0.1.1.dist-info/entry_points.txt +2 -0
planager/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""planager — Feature plans for LLM-assisted development."""
|
planager/cli.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""CLI entry point: `planager init` sets up a project for plan-based development."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import shutil
|
|
7
|
+
import sys
|
|
8
|
+
from importlib.resources import files
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
SNIPPET_MARKER = "<!-- planager:start -->"
|
|
12
|
+
SNIPPET_END_MARKER = "<!-- planager:end -->"
|
|
13
|
+
|
|
14
|
+
TEMPLATES = files("planager.templates")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_template_path() -> Path:
|
|
18
|
+
"""Resolve the templates directory to a filesystem path."""
|
|
19
|
+
return Path(str(TEMPLATES))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def init_project(target: Path) -> list[str]:
|
|
23
|
+
"""Install planager files into *target* project directory.
|
|
24
|
+
|
|
25
|
+
Returns a list of actions taken (for user feedback).
|
|
26
|
+
"""
|
|
27
|
+
actions: list[str] = []
|
|
28
|
+
template_dir = get_template_path()
|
|
29
|
+
|
|
30
|
+
# 1. Create .plans/ directory
|
|
31
|
+
plans_dir = target / ".plans"
|
|
32
|
+
if not plans_dir.exists():
|
|
33
|
+
plans_dir.mkdir(parents=True)
|
|
34
|
+
actions.append("Created .plans/")
|
|
35
|
+
else:
|
|
36
|
+
actions.append(".plans/ already exists, skipped")
|
|
37
|
+
|
|
38
|
+
# 2. Copy skill files
|
|
39
|
+
skills_dir = target / ".claude" / "skills"
|
|
40
|
+
for skill_name in ("plan", "plan-status"):
|
|
41
|
+
skill_dest = skills_dir / skill_name / "SKILL.md"
|
|
42
|
+
skill_src = template_dir / skill_name / "SKILL.md"
|
|
43
|
+
|
|
44
|
+
if skill_dest.exists():
|
|
45
|
+
actions.append(f".claude/skills/{skill_name}/SKILL.md already exists, skipped")
|
|
46
|
+
else:
|
|
47
|
+
skill_dest.parent.mkdir(parents=True, exist_ok=True)
|
|
48
|
+
shutil.copy2(str(skill_src), str(skill_dest))
|
|
49
|
+
actions.append(f"Created .claude/skills/{skill_name}/SKILL.md")
|
|
50
|
+
|
|
51
|
+
# 3. Append CLAUDE.md snippet
|
|
52
|
+
claude_md = target / "CLAUDE.md"
|
|
53
|
+
snippet = (template_dir / "CLAUDE.md.snippet").read_text()
|
|
54
|
+
wrapped_snippet = f"{SNIPPET_MARKER}\n{snippet}{SNIPPET_END_MARKER}\n"
|
|
55
|
+
|
|
56
|
+
if claude_md.exists():
|
|
57
|
+
existing = claude_md.read_text()
|
|
58
|
+
if SNIPPET_MARKER in existing:
|
|
59
|
+
actions.append("CLAUDE.md already has planager snippet, skipped")
|
|
60
|
+
else:
|
|
61
|
+
with claude_md.open("a") as f:
|
|
62
|
+
f.write("\n" + wrapped_snippet)
|
|
63
|
+
actions.append("Appended planager snippet to CLAUDE.md")
|
|
64
|
+
else:
|
|
65
|
+
claude_md.write_text(wrapped_snippet)
|
|
66
|
+
actions.append("Created CLAUDE.md with planager snippet")
|
|
67
|
+
|
|
68
|
+
return actions
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def main(argv: list[str] | None = None) -> int:
|
|
72
|
+
parser = argparse.ArgumentParser(
|
|
73
|
+
prog="planager",
|
|
74
|
+
description="Feature plans for LLM-assisted development.",
|
|
75
|
+
)
|
|
76
|
+
sub = parser.add_subparsers(dest="command")
|
|
77
|
+
|
|
78
|
+
init_parser = sub.add_parser(
|
|
79
|
+
"init",
|
|
80
|
+
help="Set up the current project for plan-based development.",
|
|
81
|
+
)
|
|
82
|
+
init_parser.add_argument(
|
|
83
|
+
"--path",
|
|
84
|
+
type=Path,
|
|
85
|
+
default=Path.cwd(),
|
|
86
|
+
help="Project root directory (default: current directory).",
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
args = parser.parse_args(argv)
|
|
90
|
+
|
|
91
|
+
if args.command is None:
|
|
92
|
+
parser.print_help()
|
|
93
|
+
return 1
|
|
94
|
+
|
|
95
|
+
if args.command == "init":
|
|
96
|
+
target = args.path.resolve()
|
|
97
|
+
if not target.is_dir():
|
|
98
|
+
print(f"Error: {target} is not a directory.", file=sys.stderr)
|
|
99
|
+
return 1
|
|
100
|
+
|
|
101
|
+
actions = init_project(target)
|
|
102
|
+
print(f"Initialized planager in {target}\n")
|
|
103
|
+
for action in actions:
|
|
104
|
+
print(f" {action}")
|
|
105
|
+
print("\nDone. Start a Claude Code session and plans will work automatically.")
|
|
106
|
+
return 0
|
|
107
|
+
|
|
108
|
+
return 1
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if __name__ == "__main__":
|
|
112
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
|
|
2
|
+
# Feature Plans
|
|
3
|
+
|
|
4
|
+
This project uses **planager** for structured feature planning. Plans are
|
|
5
|
+
markdown files in `.plans/` with phased steps and checkboxes.
|
|
6
|
+
|
|
7
|
+
## Automatic behavior
|
|
8
|
+
|
|
9
|
+
### On session start
|
|
10
|
+
|
|
11
|
+
Check `.plans/` for any plans with `status: in-progress` or `status: blocked`.
|
|
12
|
+
If any exist, briefly note them to the user (e.g. "There's an in-progress plan
|
|
13
|
+
for <title>"). If the user's request clearly relates to one, read it and resume
|
|
14
|
+
from the first unchecked step. Don't force it — if the user is asking about
|
|
15
|
+
something unrelated, just mention the plan exists and move on.
|
|
16
|
+
|
|
17
|
+
### When starting new feature work
|
|
18
|
+
|
|
19
|
+
Before writing code for a non-trivial feature, create a plan:
|
|
20
|
+
|
|
21
|
+
1. Ask the user for a brief description (if not already provided).
|
|
22
|
+
2. Explore the codebase to understand what's involved.
|
|
23
|
+
3. Draft a phased plan with concrete, checkable steps.
|
|
24
|
+
4. Present the plan to the user for approval.
|
|
25
|
+
5. Save the approved plan to `.plans/<feature-slug>.md`.
|
|
26
|
+
6. Begin implementation from Phase 1.
|
|
27
|
+
|
|
28
|
+
Skip planning for trivial tasks (single-file fixes, typos, config changes).
|
|
29
|
+
Use judgment — if the work spans multiple files or sessions, it deserves a plan.
|
|
30
|
+
|
|
31
|
+
### While working on a planned feature
|
|
32
|
+
|
|
33
|
+
- Check off steps (`- [x]`) as they are completed.
|
|
34
|
+
- Add notes to the `## Notes` section for decisions, blockers, or alternatives
|
|
35
|
+
considered.
|
|
36
|
+
- Update the `updated` date in frontmatter.
|
|
37
|
+
- Set `status: in-progress` when work begins (if still `planning`).
|
|
38
|
+
- If blocked, set `status: blocked` and note the reason.
|
|
39
|
+
|
|
40
|
+
### On completion
|
|
41
|
+
|
|
42
|
+
- Set `status: done` in frontmatter.
|
|
43
|
+
- Write a brief summary in `## Notes` of what was built.
|
|
44
|
+
- Check off all remaining steps.
|
|
45
|
+
|
|
46
|
+
## Plan format
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
---
|
|
50
|
+
feature: short-slug
|
|
51
|
+
title: Human-Readable Title
|
|
52
|
+
status: planning | in-progress | blocked | done
|
|
53
|
+
created: YYYY-MM-DD
|
|
54
|
+
updated: YYYY-MM-DD
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Context
|
|
58
|
+
|
|
59
|
+
What the feature is, why it matters, constraints, links to issues or docs.
|
|
60
|
+
|
|
61
|
+
## Phase 1: <title>
|
|
62
|
+
|
|
63
|
+
Brief description of this phase.
|
|
64
|
+
|
|
65
|
+
- [ ] Step description
|
|
66
|
+
- [ ] Step description
|
|
67
|
+
|
|
68
|
+
## Phase 2: <title>
|
|
69
|
+
|
|
70
|
+
- [ ] Step description
|
|
71
|
+
|
|
72
|
+
## Notes
|
|
73
|
+
|
|
74
|
+
Running log of decisions, blockers, things tried.
|
|
75
|
+
```
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# /plan — Create or resume a feature plan
|
|
2
|
+
|
|
3
|
+
When the user invokes `/plan`, follow this workflow.
|
|
4
|
+
|
|
5
|
+
## If given a description (e.g. `/plan add dark mode support`)
|
|
6
|
+
|
|
7
|
+
1. Choose a short slug from the description (e.g. `dark-mode`).
|
|
8
|
+
2. Check if `.plans/<slug>.md` already exists.
|
|
9
|
+
- If it does and is `in-progress`, switch to the **resume** flow below.
|
|
10
|
+
- If it does and is `done`, tell the user and ask if they want a new plan.
|
|
11
|
+
3. Explore the codebase to understand what the feature involves:
|
|
12
|
+
- Read relevant files, check existing patterns, identify what needs to change.
|
|
13
|
+
4. Draft a phased plan with concrete steps. Each step should be small enough
|
|
14
|
+
to complete in one action (a file edit, a test run, etc.).
|
|
15
|
+
5. Present the plan to the user. Ask for approval or adjustments.
|
|
16
|
+
6. Save the approved plan to `.plans/<slug>.md` with `status: planning`.
|
|
17
|
+
7. Ask the user if they want to begin implementation now.
|
|
18
|
+
- If yes, set `status: in-progress` and start from Phase 1, step 1.
|
|
19
|
+
|
|
20
|
+
## If invoked without a description (e.g. just `/plan`)
|
|
21
|
+
|
|
22
|
+
1. Glob `.plans/*.md` and read the frontmatter of each.
|
|
23
|
+
2. List any `in-progress` or `blocked` plans.
|
|
24
|
+
3. If there are in-progress plans, ask the user:
|
|
25
|
+
- Resume one of them? (default if there's only one)
|
|
26
|
+
- Or create a new plan?
|
|
27
|
+
4. If creating new, ask for a brief description and follow the flow above.
|
|
28
|
+
|
|
29
|
+
## Resume flow
|
|
30
|
+
|
|
31
|
+
1. Read the full plan file.
|
|
32
|
+
2. Summarize current status: which phases are done, what's next.
|
|
33
|
+
3. Begin work from the first unchecked step.
|
|
34
|
+
4. Follow the standard plan update behavior (check steps, add notes, update
|
|
35
|
+
frontmatter) as you work.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# /plan-status — Show status of all feature plans
|
|
2
|
+
|
|
3
|
+
When the user invokes `/plan-status`, do the following:
|
|
4
|
+
|
|
5
|
+
1. Glob `.plans/*.md` to find all plan files.
|
|
6
|
+
2. If no plans exist, say so and exit.
|
|
7
|
+
3. For each plan file, read it and extract:
|
|
8
|
+
- `feature` and `title` from frontmatter
|
|
9
|
+
- `status` from frontmatter
|
|
10
|
+
- Checkbox counts: total `- [ ]` and `- [x]` lines per `## Phase N:` section
|
|
11
|
+
- Overall progress: completed steps / total steps
|
|
12
|
+
4. Print a summary table, for example:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Feature Status Progress
|
|
16
|
+
─────────────── ─────────── ────────────────
|
|
17
|
+
auth in-progress Phase 2: 3/7
|
|
18
|
+
dark-mode planning Phase 1: 0/4
|
|
19
|
+
api-v2 done 5/5
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
5. If any plan is `blocked`, show the reason from the Notes section if available.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: planager
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Feature plans for LLM-assisted development. One command sets up your project so coding agents automatically create, follow, and maintain structured plans.
|
|
5
|
+
Project-URL: Repository, https://github.com/forest-d/planager
|
|
6
|
+
Author: forest-d
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Keywords: claude,codex,development,llm,planning
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# planager
|
|
17
|
+
|
|
18
|
+
Feature plans for LLM-assisted development.
|
|
19
|
+
|
|
20
|
+
One command sets up your project so coding agents (Claude Code, Codex, etc.)
|
|
21
|
+
automatically create, follow, and maintain structured feature plans across
|
|
22
|
+
sessions.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cd your-project
|
|
28
|
+
uvx planager init
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
That's it. No runtime dependencies, no background processes. The command copies
|
|
32
|
+
a few template files into your project and you're done.
|
|
33
|
+
|
|
34
|
+
## What it does
|
|
35
|
+
|
|
36
|
+
After `planager init`, your project gets:
|
|
37
|
+
|
|
38
|
+
- **`.plans/`** — directory where feature plans live (markdown files).
|
|
39
|
+
- **`.claude/skills/plan/`** — a `/plan` slash command for creating and resuming plans.
|
|
40
|
+
- **`.claude/skills/plan-status/`** — a `/plan-status` slash command for checking progress.
|
|
41
|
+
- **CLAUDE.md snippet** — instructions that make the agent automatically discover
|
|
42
|
+
and follow plans without you having to ask.
|
|
43
|
+
|
|
44
|
+
## How it works
|
|
45
|
+
|
|
46
|
+
Plans are markdown files with frontmatter, phased steps, and checkboxes:
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
---
|
|
50
|
+
feature: auth
|
|
51
|
+
title: User Authentication
|
|
52
|
+
status: in-progress
|
|
53
|
+
created: 2026-04-18
|
|
54
|
+
updated: 2026-04-18
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Context
|
|
58
|
+
|
|
59
|
+
Implement email/password authentication with session management.
|
|
60
|
+
|
|
61
|
+
## Phase 1: Database schema
|
|
62
|
+
|
|
63
|
+
- [x] Create users table migration
|
|
64
|
+
- [x] Add password hashing utility
|
|
65
|
+
- [ ] Add session table migration
|
|
66
|
+
|
|
67
|
+
## Phase 2: API endpoints
|
|
68
|
+
|
|
69
|
+
- [ ] POST /login
|
|
70
|
+
- [ ] POST /register
|
|
71
|
+
|
|
72
|
+
## Notes
|
|
73
|
+
|
|
74
|
+
Using bcrypt for hashing. Decided against JWT — sessions are simpler for now.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The CLAUDE.md snippet teaches the agent to:
|
|
78
|
+
|
|
79
|
+
1. **Check for in-progress plans** at the start of each session.
|
|
80
|
+
2. **Create plans** before starting non-trivial features.
|
|
81
|
+
3. **Update plans** as work progresses (check off steps, add notes).
|
|
82
|
+
4. **Mark plans done** when a feature is complete.
|
|
83
|
+
|
|
84
|
+
No special tools or MCP servers — the agent reads and writes plain markdown files.
|
|
85
|
+
|
|
86
|
+
## Slash commands
|
|
87
|
+
|
|
88
|
+
### `/plan`
|
|
89
|
+
|
|
90
|
+
Create a new feature plan or resume an existing one.
|
|
91
|
+
|
|
92
|
+
- With a description: `/plan add dark mode support` — explores the codebase,
|
|
93
|
+
drafts a phased plan, asks for approval.
|
|
94
|
+
- Without: `/plan` — lists in-progress plans and offers to resume or create new.
|
|
95
|
+
|
|
96
|
+
### `/plan-status`
|
|
97
|
+
|
|
98
|
+
Show progress across all plans:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Feature Status Progress
|
|
102
|
+
─────────────── ─────────── ────────────────
|
|
103
|
+
auth in-progress Phase 2: 3/7
|
|
104
|
+
dark-mode planning Phase 1: 0/4
|
|
105
|
+
api-v2 done 5/5
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Idempotent
|
|
109
|
+
|
|
110
|
+
Running `uvx planager init` again is safe — it skips files that already exist
|
|
111
|
+
and won't duplicate the CLAUDE.md snippet.
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
planager/__init__.py,sha256=epy7RGoiiClOFva8dyElWibyIU08Gg-yfLZa4uPhsQA,63
|
|
2
|
+
planager/cli.py,sha256=YR6mSHleEA-W3zE3qt-fArBFlIbu332biGMc5j2K18g,3440
|
|
3
|
+
planager/templates/CLAUDE.md.snippet,sha256=CitSzrtFmsinSA5czhct5tKBLM9GJtiHtZK07AysQgg,2131
|
|
4
|
+
planager/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
planager/templates/plan/SKILL.md,sha256=thTGhlRWHXtcNqMQbAFhZfsJgdvSEI_25w9-0i3NDC0,1607
|
|
6
|
+
planager/templates/plan-status/SKILL.md,sha256=tLq43-wYicmIdFy6dwtXOfIIlu4F-3NL9VTHSfUuB2o,868
|
|
7
|
+
planager-0.1.1.dist-info/METADATA,sha256=AzRxt7hfdsuQO3lpKV2q-dEB0Qh7xpOUrNW4AowClsY,3222
|
|
8
|
+
planager-0.1.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
9
|
+
planager-0.1.1.dist-info/entry_points.txt,sha256=RNKI-EOTSugD0VaOWu5AguWHdE_otCzdSNG0-vLW4dc,47
|
|
10
|
+
planager-0.1.1.dist-info/RECORD,,
|