The .planning directory

Every file DevFlow creates, who writes it, and who reads it back.

.planning/ is the project’s memory. It is the reason DevFlow survives context resets: nothing important lives in the conversation.

.planning/
  PROJECT.md              vision, context, `kind` — loaded on nearly every operation
  REQUIREMENTS.md         scoped v1/v2 requirements with stable IDs
  ROADMAP.md              objectives in dependency order, with checkboxes
  STATE.md                decisions, blockers, position, session memory
  MILESTONES.md           archive of completed milestones
  config.json             workflow configuration
  state.json              machine-readable position mirror

  research/               domain research from new-project
  codebase/               brownfield mapping from map-codebase
  todos/
    pending/              captured ideas awaiting work
    done/
  debug/                  active debug sessions
    resolved/
  decisions/
    pending/              parked DECISION-NNN.md awaiting your answer
  milestones/             archived milestone directories

  objectives/
    NN-objective-name/
      OBJECTIVE.md        goal, success criteria, `work` type
      CONTEXT.md          your implementation preferences (discuss-objective)
      RESEARCH.md         ecosystem research (research-objective)
      NN-YY-JOB.md        atomic execution plan, one per job
      NN-YY-SUMMARY.md    execution outcome, decisions, evidence
      VERIFICATION.md     post-execution verification results
      UAT.md              user acceptance walkthrough
      verification/       Maestro YAML flows, capture manifests

The files you will actually read

PROJECT.md

Short by design — it is loaded on nearly every operation, so every line costs context on every command. Vision, constraints, key decisions, and the project kind on frontmatter.

ROADMAP.md

Objectives, ordered, with success criteria and completion checkboxes. The numbers here are what you pass to /devflow:build.

Checkbox state can drift from reality if work happened outside DevFlow. /devflow:sync-roadmap reconciles it against on-disk SUMMARY.md presence.

STATE.md

The living memory. Current position, decisions with rationale, open blockers, session history. Written by df-tools state subcommands rather than by hand:

df-tools state add-decision --objective 4 --summary "Chose X" --rationale "because Y"
df-tools state add-blocker --text "Waiting on API key"
df-tools state resolve-blocker --text "Waiting on API key"

SUMMARY.md

One per job. Written by the executor when a job finishes: what it did, what it decided, what evidence exists that it worked. The verify-completion Stop hook checks the most recent one for task evidence and failure markers.

SUMMARY.md files are also what /devflow:sync-roadmap and df-tools gh sync-release read — presence of a summary is the on-disk signal that a job actually ran.

Who writes what

FileWritten byRead by
PROJECT.mdnew-projectalmost everything
REQUIREMENTS.mdroadmappermilestone audit
ROADMAP.mdroadmapper, objective opsbuild, status, gh-sync
STATE.mddf-tools state, executorstatus, resume
CONTEXT.mddiscuss-objectiveplanner
RESEARCH.mdobjective-researcherplanner
JOB.mdplannerexecutor, job-checker
SUMMARY.mdexecutorverifier, sync-roadmap, gh sync-release
VERIFICATION.mdverifiergh comment, milestone audit

Markers and caches

A handful of dotfiles coordinate the hooks. You will rarely touch them, but they explain otherwise-mysterious behaviour:

FilePurpose
.skill-activeWritten by df-tools skill-active --start. Its presence is what lets the edit gate allow edits. Carries an expires_at (8h default).
.edit-overrideWritten by route-intent when your prompt contains an override phrase. Single-turn, consumed by the edit gate.
.gh-mapping.jsonObjective number → GitHub issue number. Commit this.

Should .planning be committed?

By default, yes — planning.commit_docs is true. Planning artifacts are project documentation, and committing them means the roadmap and decisions are visible in review and survive a fresh clone.

For client or sensitive work, set commit_docs: false and add .planning/ to .gitignore. Planning stays local; only code is committed.