From project-management-plugin
Manages project and task state in .claude/projects/{project-id}/ using atomic writes for data integrity and session continuity in Claude Code projects.
npx claudepluginhub markus41/claude --plugin project-planner-pluginThis skill uses the workspace's default tool permissions.
All project state lives under `.claude/projects/{project-id}/` relative to the repository root. This location is chosen deliberately: it is inside the `.claude/` directory (which is already gitignored in most Claude Code configurations), it is scoped to the project by ID (supporting multiple concurrent projects), and it is readable by all hook scripts and skills without any path resolution logic.
Persists task state across sessions via state.md for cross-session continuity and generates project-map.md. Use for long/noisy sessions, explicit save/compress requests, project mapping, or stale context.
Updates project_state.md, scans task directories via Bash, detects inconsistencies like empty/orphaned files, organizes structure after phase activities or task completion.
Manages development session context via tiered summarization (quick updates, full checkpoints, archives) for preservation and resumability at breakpoints or after breaks.
Share bugs, ideas, or general feedback.
All project state lives under .claude/projects/{project-id}/ relative to the repository root. This location is chosen deliberately: it is inside the .claude/ directory (which is already gitignored in most Claude Code configurations), it is scoped to the project by ID (supporting multiple concurrent projects), and it is readable by all hook scripts and skills without any path resolution logic.
The full directory layout is:
.claude/projects/{project-id}/
project.json — Top-level project record (validates against project.schema.json)
tasks.json — Master list of all task objects (validates against task.schema.json per item)
progress/
log.md — Append-only human-readable execution log
velocity.json — Rolling velocity metrics updated after each task completes
research/
{task-id}.md — Research brief per task (written by research-protocol skill)
checkpoints/
checkpoint-{n}.json — Numbered snapshots of tasks.json at key milestones
temp/
.write-{uuid} — Temporary files used during atomic write operations
The temp/ directory is transient. Any file matching .write-* that is older than 5 minutes can be safely deleted — it is a failed atomic write that was abandoned mid-operation. The checkpoint and research directories grow over time; they are never pruned automatically. The progress log is append-only and must never be truncated or overwritten.
All writes to project.json and tasks.json follow a strict atomic write protocol to prevent partial-write corruption that would leave the project in an unrecoverable state.
The protocol has three steps. First, compute the new JSON content in memory and validate it against the relevant schema. If validation fails, the write is aborted and an error is appended to progress/log.md — the existing file is never touched. Second, write the validated content to a temporary file at temp/.write-{uuid} where the UUID is generated fresh for each write operation. Third, rename the temporary file to the target path using an atomic filesystem rename. On POSIX systems this is a single mv operation. On Windows (where the project currently runs), the rename must replace an existing file, which requires deleting the target first and then renaming — this brief window is acceptable because the previous valid state is recoverable from the most recent checkpoint.
Under no circumstances should the target file be opened for direct write. Line-by-line or in-place edits to state files are forbidden. The entire file is always regenerated from the in-memory state object, serialized to JSON, and written atomically.
The tasks.json file is a JSON object with a single key tasks containing an array of task objects. The array is the canonical source of truth for all task state. The order of tasks in the array reflects the order they were created, not their execution order (which is determined dynamically by the scheduler based on dependencies and priority).
Each task object in the array conforms to task.schema.json. The id field is the primary key. Lookups by ID should iterate the array; no secondary index is maintained in this file. The tasks array includes tasks at all levels of the hierarchy — epics, stories, tasks, subtasks, and micro-tasks are all represented as peers in the flat list, with parent-child relationships expressed through the subtasks array on parent tasks.
When a task is decomposed into subtasks, the parent task's subtasks field is updated with the child IDs, and the new child tasks are appended to the tasks array. The parent task's status transitions to IN_PROGRESS at this point — a parent task is never directly executed; it is COMPLETE only when all its subtasks are COMPLETE.
After every phase completion and after every 10 task completions (whichever comes first), the current state of tasks.json is written as a numbered checkpoint to checkpoints/checkpoint-{n}.json. The checkpoint number increments monotonically from 1. Only the last 10 checkpoints are retained; when checkpoint-11 is written, checkpoint-1 is deleted.
Checkpoints serve as recovery points. If tasks.json becomes corrupted or inconsistent (e.g., due to an interrupted atomic write), the most recent valid checkpoint is used to reconstruct the state. A checkpoint is considered valid if it can be parsed as JSON and at least one task object passes schema validation. The recovery logic does not require full schema compliance — partial recovery is preferable to no recovery.
Checkpoints are named with zero-padded numbers (checkpoint-001.json through checkpoint-010.json) so that lexicographic sort correctly identifies the newest checkpoint.
The progress/log.md file is append-only. Nothing is ever deleted or overwritten in this file. Each entry is a markdown block beginning with a timestamp line in the format ## YYYY-MM-DDTHH:MM:SSZ — {event-type}.
Standard event types are: TASK_STARTED, TASK_COMPLETE, TASK_BLOCKED, TASK_RESEARCHED, PHASE_COMPLETE, CHECKPOINT_WRITTEN, ERROR, SYNC_TO_{PLATFORM}, and LOOP_ITERATION. Each event block includes the task ID (where applicable), the previous status, the new status, and any relevant detail (e.g., for TASK_COMPLETE, the actual_minutes spent; for ERROR, the full error message; for SYNC, the external ID assigned).
The log is not parsed by the autonomous loop for scheduling decisions — those are made from tasks.json. The log exists for human audit and post-mortem analysis. It is also the source of data for the velocity calculation.
When the autonomous loop is resumed after an interrupted session, it performs a reconciliation step before executing any tasks. The reconciliation compares the in-progress tasks recorded in tasks.json with the last checkpoint to determine whether any tasks were left in a transitional state.
A task is considered transitional if its status is IN_RESEARCH or IN_PROGRESS at the time the session ended. These statuses indicate the executor was mid-work when the session terminated. For each transitional task, the reconciler applies the following heuristic: if the task's research file exists and is recent (written after the task's created_at), transition the status to RESEARCHED; otherwise, reset it to PENDING. This is conservative — it prefers re-doing work over asserting false completion.
Tasks in VALIDATING status are treated as if they are IN_PROGRESS — validation did not complete, so the task must be re-executed and re-validated.
Tasks in COMPLETE, BLOCKED, or CANCELLED status are never reset during reconciliation regardless of checkpoint state. These terminal (or intentionally paused) states are respected across sessions.
A task is considered stale when it has been in IN_PROGRESS status for longer than 4 times its estimate_minutes without a TASK_COMPLETE event appearing in the progress log. The stale threshold is generous to account for research overhead and validation retries, but it is bounded to prevent infinitely hung tasks from blocking the entire project.
When a stale task is detected on loop resume, it is automatically reset to PENDING and an ERROR entry is written to the progress log explaining the stale reset. The task's estimate is not modified — the original estimate is preserved so that velocity calculations remain accurate. If the same task becomes stale twice, it is transitioned to BLOCKED with a blocked_reason of "Stale twice — requires human review" and the loop skips it entirely until a human intervenes.
Research files associated with a stale-reset task are not deleted — they may contain valid findings even if the execution did not complete. The next execution pass will find the existing research file, check its timestamp against the 24-hour TTL, and reuse it if still fresh.