planledger
Planledger stores independent, structured, versioned implementation plans and renders each plan into one standalone rendered Markdown handoff file.
Product contract
- Planledger stores plans only.
- Each plan is independent.
- The main user is a coding agent through
skills/planledger/SKILL.md. - A done plan must contain todo items, acceptance criteria, target files, and validation commands.
- Planledger has no external task-manager integration.
What it does
- stores independent plans under the configured Planledger storage directory, for example
.planledger/plans/plan-0001/or../planledger-state/planledger/plans/plan-0001/; - versions every meaningful plan change;
- keeps each plan as modular component files;
- renders a standalone Markdown artifact for human or coding-agent handoff;
- enforces handoff quality guardrails before a plan can be marked
done.
planledger is not a task manager, does not store goals, and has no external task-manager integration.
Plan identity
Each plan has a stored local ID and derived cross-ledger references:
local ID: plan-0001
global ref: pl:plan-0001
file ref: pl-plan-0001
Canonical global references use <ledger>:<kind>-<number>, such as
tl:task-0001, al:adr-0002, sw:spec-0003, and pl:plan-0004.
File aliases such as pl-plan-0001 are accepted as selectors. Uppercase aliases
are input compatibility only; Planledger always emits lowercase canonical refs.
The global and file refs are derived from the configured ledger code and local
ID, not stored as a second identity source. Cross-ledger refs are identifiers,
not task-manager integration.
Release maturity
Planledger is currently a beta package (Development Status :: 4 - Beta). It is intended for planning-only workflows and standalone handoff artifacts. Beta status means the project is suitable for early adopter use, but releases should pass the documented maintainer gate before publication.
Install
pip install -e .
Quick start for coding agents
The CLI is the only supported mutation path. The rendered Markdown artifact is the deliverable.
# Check workspace state
planledger status
planledger status --check
# Initialize if needed
planledger init
# Create a new independent plan. The new plan becomes active.
planledger plan create --title "Add feature A" --request "Please review how we can add feature A."
# Populate components on the active plan (inspect repository files first)
planledger plan component set context --file context.md
planledger plan component set approach --file approach.md
planledger plan component set todo_items --file todos.md
planledger plan component set target_files --file target_files.md
planledger plan component set validation --file validation.md
planledger plan component set risks --file risks.md
# Override the active plan when needed
planledger plan show --plan plan-0001
planledger plan activate plan-0001
# Global and file selectors are also accepted:
planledger plan show pl:plan-0001
planledger plan show pl-plan-0001
# Build, validate, mark done
planledger plan build
planledger plan validate
planledger plan status done --reason "Ready for coding agent handoff."
# Export rendered plan to workspace root for the harness
planledger plan export
Use a **workshop** first when a request is about shaping a feature, finding examples, clarifying behavior, product rules, BDD scenarios, acceptance scenarios, or requirement exploration. Use a **plan** directly when the request is implementation-oriented, asks for a coding-agent handoff, names target files, revises an existing `plan-000X`, or explicitly asks for a PLAN.md-style artifact. Do not ask which mode to use unless both paths are equally valid; prefer workshop-first when `prompt_profiles.planning_workshop.enabled = true` and the request is product or behavior shaping.
## Todo item template
Every todo item in the `todo_items` component should follow this structure:
```md
### TODO-001: <action-oriented title>
**Target files**
- [`path/to/file.py`](path/to/file.py) — why this file changes.
**Acceptance criteria**
- [ ] Observable outcome.
- [ ] Regression or edge case covered.
**Validation**
- `python -m pytest path/to/test_file.py -q`
Handoff quality guardrails
done is a handoff-readiness state, not an implementation-completed state. A plan cannot be marked done unless:
todo_itemscontains at least one### TODO-NNNheading.- Every todo item has an Acceptance criteria section with at least one checkbox.
- Every todo item has a Target files section with at least one file reference.
target_filescontains at least one repo-relative file path or Markdown link.validationcontains at least one validation command.- No required component contains placeholder content (
TBD,TODO:,<fill>, etc.). open_questionscontains no unresolved required questions (- [ ] REQUIRED:).
Plan validation means the plan artifact is structurally ready for handoff. It does not mean implementation tests have passed.
Plan components
Each plan stores these components:
| Component | Required | Description |
|---|---|---|
request |
yes | Original human request |
summary |
yes | Executive verdict |
context |
yes | Repository context and evidence |
open_questions |
no | Unresolved questions |
assumptions |
no | Assumed facts |
approach |
yes | Proposed implementation approach |
todo_items |
yes | Structured todo items |
target_files |
yes | Files that will change |
validation |
yes | Validation plan and commands |
risks |
yes | Risks and mitigations |
rollback |
no | Rollback or repair strategy |
notes |
no | Additional notes |
Rendered Markdown example
---
planledger_schema: planledger.rendered_plan.v1
plan_id: plan-0003
id: plan-0003
kind: plan
ledger_code: pl
global_ref: pl:plan-0003
file_ref: pl-plan-0003
title: Add feature A
status: done
version: 5
generated_at: 2026-06-09T12:00:00Z
---
# Add feature A
Plan: `plan-0003`
Ref: `pl:plan-0003`
Version: `v0005`
Status: `done`
## Executive verdict
**Ready for coding-agent implementation.**
One paragraph summarizing the decision and scope.
## Repository context and evidence
| Area | Finding | Evidence |
| ---- | --------------------------------------------------------- | ----------------------------------------- |
| CLI | Current command implementation is in `planledger/cli.py`. | Function `plan_create`, `plan_build`, ... |
## Proposed approach
Explain the design and why it is acceptable.
## Todo items
### TODO-001: Implement feature A
**Target files**
- [`planledger/cli.py`](planledger/cli.py)
**Acceptance criteria**
- [ ] CLI exposes the new behavior.
**Validation**
- `python -m pytest -q`
Filesystem layout
<configured planledger_dir>/
storage.yaml
plans/
plan-0001/
plan.yaml
components/
rendered/
versions/
The config file may be planledger.toml or .planledger.toml. storage.planledger_dir is resolved relative to the config root when it is a relative path, so sibling storage such as ../planledger-state/planledger is valid.
[ledger]
code = "pl"
name = "planledger"
[project]
name = "my-project"
uuid = "..."
[storage]
planledger_dir = "../planledger-state/planledger"
Configs without [ledger] remain valid and default to code pl and name
planledger.
CLI surface
planledger init [--project-name NAME] [--planledger-dir .planledger] [--hidden-config]
planledger status [--check] [--json]
planledger info [--plan PLAN_ID | --workshop WORKSHOP_ID] [--paths-only] [--no-components] [--json]
planledger doctor [--json]
planledger next-action [PLAN_ID] [--json]
planledger plan create --title TITLE [--request TEXT | --request-file PATH | --stdin] [--status new|in_progress]
planledger plan activate PLAN_ID
planledger plan list [--status STATUS] [--json]
planledger plan show [PLAN_ID] [--plan PLAN_ID] [--component KEY] [--rendered] [--json]
planledger plan status [PLAN_ID] [--plan PLAN_ID] STATUS --reason TEXT
planledger plan cancel [PLAN_ID] [--plan PLAN_ID] --reason TEXT
planledger plan component list [PLAN_ID] [--plan PLAN_ID] [--json]
planledger plan component show COMPONENT [--plan PLAN_ID]
planledger plan component set COMPONENT [--plan PLAN_ID] (--text TEXT | --file PATH | --stdin) [--reason TEXT]
planledger plan component append COMPONENT [--plan PLAN_ID] (--text TEXT | --file PATH | --stdin) [--reason TEXT]
planledger plan build [PLAN_ID] [--plan PLAN_ID] [--out PATH] [--print] [--include-empty] [--json]
planledger plan export [PLAN_ID] [--plan PLAN_ID] [--out PATH] [--include-empty] [--json]
planledger plan validate [PLAN_ID] [--plan PLAN_ID] [--json]
planledger plan versions [PLAN_ID] [--plan PLAN_ID] [--json]
planledger plan diff [PLAN_ID] [--plan PLAN_ID] --from v0001 --to v0002
planledger plan apply --file PATH_OR_DASH [--dry-run]
planledger info is a read-only inventory of everything stored: workspace and
storage paths, schema version and id counters, the active plan/workshop, and
every plan and workshop with status, version, component fill-state, rendered
artifact path, and disk footprint. Use status for a quick health/counts
snapshot plus the active plan; use info for the full stored inventory.
planledger info # full human inventory
planledger --json info | jq . # machine-readable inventory
planledger info --plan plan-0001 # full detail for one plan
planledger info --paths-only # just the resolved paths
planledger info --no-components # drop per-component fill-state
Structured bundle workflow
Agents can create or update plans through planledger.structured_plan.v1 bundles.
Use plan apply --file - --dry-run before large multi-component updates or when
the JSON is hand-written. For small targeted updates, direct plan apply --file -
is acceptable and does not require a temporary file:
cat <<'JSON' | planledger plan apply --file - --dry-run
{ "schema": "planledger.structured_plan.v1", "operation": "update", "plan_id": "plan-0001", "components": { "summary": "..." } }
JSON
cat <<'JSON' | planledger plan apply --file -
{ "schema": "planledger.structured_plan.v1", "operation": "update", "plan_id": "plan-0001", "components": { "summary": "..." } }
JSON
Stdin input
Component commands and plan create accept --stdin and --file - for multiline
input without temporary files:
cat <<'MD' | planledger plan component set context --stdin --reason "Record evidence."
Repository evidence...
MD
cat <<'JSON' | planledger plan apply --file -
{ "schema": "planledger.structured_plan.v1", ... }
JSON
Plan export
planledger plan export writes the rendered Markdown to a workspace-root-relative
path (default WORKSPACE_ROOT/PLAN_ID.md). This is the recommended final handoff
step because the configured Planledger storage directory may be outside the source
workspace.
planledger plan export --plan plan-0004
# writes: ./plan-0004.md
Planning interview profile
Planledger ships an optional prompt profile named planning_workshop. When enabled, the existing Planledger skill (the single skills/planledger/SKILL.md) asks the user one plan-quality question at a time, includes a recommended answer, inspects the repository first when possible, records required questions in the open_questions component, and stops after each question.
This is a prompt profile obeyed by the skill, not a separate skill and not a CLI command that interviews you. The CLI only parses, persists, and exposes the policy.
Enable it in planledger.toml or .planledger.toml:
[prompt_profiles.planning_workshop]
enabled = true
activation = "always" # or "triggered"
question_policy = "ask_one_at_a_time"
codebase_first = true
include_recommended_answer = true
max_required_questions = 20
min_resolved_required_questions_before_done = 0
trigger_phrases = ["shape", "shape this feature", "shape this feature"]
required_question_topics = ["scope", "tests", "rollback", "risks"]
extra_guidance = """Interview the user until missing decisions are resolved. Ask exactly one question at a time and stop. Inspect the codebase first."""
activation = "always"asks during every new or updated plan while useful.activation = "triggered"activates only when the plan request contains one oftrigger_phrases. The phraseshape this featurestays valid user language, butplanning_workshopis the canonical feature name.- When the profile is active,
planledger --json next-actionreturnsnext_item == "ask_plan_question"with anagent_instruction, ornext_item == "answer_required_question"whenopen_questionsalready contains an unresolved- [ ] REQUIRED:line. planledger status --jsonexposes the configured profile underprompt_profiles.- When
min_resolved_required_questions_before_doneis a positive number,doneis blocked until that many- [x] REQUIRED:questions exist (default0stays permissive).planledger doctorwarns about unknown or invalid profile field values.
The profile does not create planning-workshop records, does not replace open_questions, and does not change Planledger's workshop-first, plan-second scope.
Development
python -m pytest
python -m ruff check .
python -m mypy planledger
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file planledger-0.2.0.tar.gz.
File metadata
- Download URL: planledger-0.2.0.tar.gz
- Upload date:
- Size: 97.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6553389b8e96e46b3d541f742d57e250369a214c89903375cc41b608c448ab20
|
|
| MD5 |
cc3b33eae8123ec8260654775395a460
|
|
| BLAKE2b-256 |
6b11df972782b7ac047b10623521009dac4fd7daf359a4f90cd63bc359c31674
|
File details
Details for the file planledger-0.2.0-py3-none-any.whl.
File metadata
- Download URL: planledger-0.2.0-py3-none-any.whl
- Upload date:
- Size: 53.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36a8d47e8ba4efe4c6e7d8b571ff195a053dffc8ae42b80f85731ca97d8541be
|
|
| MD5 |
612180a104715f928fb7aba221779eb5
|
|
| BLAKE2b-256 |
64e46057e2f93d73b3c2de10cb15452d90ee6b8f38ac79725f35950881edd12a
|