Plan Schema

Reference for the plan.json file structure.

Overview

A plan.json file contains:

  • meta: Project metadata

  • summary: Calculated progress statistics

  • phases: Array of phases, each containing tasks

  • decisions: Pending and resolved decisions (optional)

  • success_metrics: Target metrics (optional)

  • blockers: Active blockers (optional)

Minimal Example

{
  "meta": {
    "project": "My Project",
    "version": "1.0.0",
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z",
    "business_plan_path": "docs/plan.md"
  },
  "summary": {
    "total_phases": 1,
    "total_tasks": 1,
    "completed_tasks": 0,
    "overall_progress": 0
  },
  "phases": [
    {
      "id": "0",
      "name": "Setup",
      "description": "Initial setup",
      "status": "pending",
      "progress": { "completed": 0, "total": 1, "percentage": 0 },
      "tasks": [
        {
          "id": "0.1.1",
          "title": "Initialize project",
          "status": "pending",
          "agent_type": null,
          "depends_on": [],
          "tracking": {}
        }
      ]
    }
  ]
}

JSON Schema Reference

The canonical schema that pv validate uses:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://shortlist.app/plan.schema.json",
  "title": "Implementation Plan",
  "description": "Schema for AI agent-consumable implementation plans",
  "type": "object",
  "required": ["meta", "summary", "phases"],
  "properties": {
    "meta": {
      "type": "object",
      "required": ["project", "version", "created_at", "updated_at", "business_plan_path"],
      "properties": {
        "project": {"type": "string"},
        "version": {"type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$"},
        "schema_version": {
          "description": "Schema version for migration support (e.g., '1.0.0')",
          "type": "string",
          "pattern": "^\\d+\\.\\d+\\.\\d+$"
        },
        "created_at": {"type": "string", "format": "date-time"},
        "updated_at": {"type": "string", "format": "date-time"},
        "business_plan_path": {"type": "string"}
      }
    },
    "summary": {
      "type": "object",
      "required": ["total_phases", "total_tasks", "completed_tasks", "overall_progress"],
      "properties": {
        "total_phases": {"type": "integer", "minimum": 0},
        "total_tasks": {"type": "integer", "minimum": 0},
        "completed_tasks": {"type": "integer", "minimum": 0},
        "in_progress_tasks": {"type": "integer", "minimum": 0},
        "blocked_tasks": {"type": "integer", "minimum": 0},
        "overall_progress": {"type": "number", "minimum": 0, "maximum": 100}
      }
    },
    "phases": {
      "type": "array",
      "items": {"$ref": "#/definitions/phase"}
    },
    "decisions": {
      "type": "object",
      "properties": {
        "pending": {
          "type": "array",
          "items": {"$ref": "#/definitions/decision"}
        },
        "resolved": {
          "type": "array",
          "items": {"$ref": "#/definitions/decision"}
        }
      }
    },
    "success_metrics": {
      "type": "object",
      "properties": {
        "business_plan_ref": {"$ref": "#/definitions/business_plan_ref"},
        "targets": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["metric", "target"],
            "properties": {
              "metric": {"type": "string"},
              "target": {"type": "string"},
              "current": {"type": ["string", "null"]}
            }
          }
        }
      }
    },
    "blockers": {
      "type": "array",
      "items": {"$ref": "#/definitions/blocker"}
    }
  },
  "definitions": {
    "status": {
      "type": "string",
      "enum": ["pending", "in_progress", "completed", "blocked", "skipped"]
    },
    "agent_type": {
      "description": "Agent type identifier. Use kebab-case (e.g., 'python-backend-engineer') or any descriptive name.",
      "oneOf": [
        {"type": "null"},
        {"type": "string", "minLength": 1}
      ]
    },
    "skill": {
      "description": "Optional skill to invoke for this task (e.g., 'frontend-design'). Skills provide specialized capabilities.",
      "oneOf": [
        {"type": "null"},
        {"type": "string", "minLength": 1}
      ]
    },
    "business_plan_ref": {
      "type": ["object", "null"],
      "properties": {
        "section": {"type": "string"},
        "lines": {
          "type": "array",
          "items": {"type": "integer"},
          "minItems": 2,
          "maxItems": 2
        },
        "key_content": {"type": "string"}
      },
      "required": ["section", "lines"]
    },
    "tracking": {
      "type": "object",
      "properties": {
        "started_at": {"type": ["string", "null"], "format": "date-time"},
        "completed_at": {"type": ["string", "null"], "format": "date-time"},
        "time_spent_minutes": {"type": ["integer", "null"], "minimum": 0},
        "notes": {"type": ["string", "null"]},
        "attempts": {"type": "integer", "minimum": 0, "default": 0},
        "last_error": {"type": ["string", "null"]},
        "assigned_agent_id": {"type": ["string", "null"]}
      }
    },
    "subtask": {
      "type": "object",
      "required": ["id", "title", "status"],
      "properties": {
        "id": {"type": "string"},
        "title": {"type": "string"},
        "status": {"$ref": "#/definitions/status"}
      }
    },
    "priority": {
      "type": ["string", "null"],
      "enum": [null, "low", "medium", "high"]
    },
    "estimated_minutes": {
      "type": ["integer", "null"],
      "minimum": 0
    },
    "task": {
      "type": "object",
      "required": ["id", "title", "status", "agent_type", "depends_on", "tracking"],
      "properties": {
        "id": {"type": "string", "pattern": "^[a-z0-9]+\\.\\d+\\.\\d+$", "description": "Task ID format: phase.section.task (e.g., '0.1.1' or 'bugs.1.1')"},
        "title": {"type": "string"},
        "status": {"$ref": "#/definitions/status"},
        "priority": {"$ref": "#/definitions/priority"},
        "estimated_minutes": {"$ref": "#/definitions/estimated_minutes"},
        "agent_type": {"$ref": "#/definitions/agent_type"},
        "skill": {"$ref": "#/definitions/skill"},
        "business_plan_ref": {"$ref": "#/definitions/business_plan_ref"},
        "depends_on": {
          "description": "Task IDs this task depends on (must be completed first)",
          "type": "array",
          "items": {"type": "string", "pattern": "^[a-z0-9]+\\.\\d+\\.\\d+$"},
          "uniqueItems": true
        },
        "subtasks": {
          "type": "array",
          "items": {"$ref": "#/definitions/subtask"}
        },
        "tracking": {"$ref": "#/definitions/tracking"}
      }
    },
    "phase": {
      "type": "object",
      "required": ["id", "name", "description", "status", "progress", "tasks"],
      "properties": {
        "id": {"type": "string"},
        "name": {"type": "string"},
        "description": {"type": "string"},
        "status": {"$ref": "#/definitions/status"},
        "progress": {
          "type": "object",
          "required": ["completed", "total", "percentage"],
          "properties": {
            "completed": {"type": "integer", "minimum": 0},
            "total": {"type": "integer", "minimum": 0},
            "percentage": {"type": "number", "minimum": 0, "maximum": 100}
          }
        },
        "tasks": {
          "type": "array",
          "items": {"$ref": "#/definitions/task"}
        }
      }
    },
    "decision": {
      "type": "object",
      "required": ["id", "question", "options"],
      "properties": {
        "id": {"type": "string"},
        "question": {"type": "string"},
        "options": {
          "type": "array",
          "items": {"type": ["string", "array"]}
        },
        "recommended": {"type": ["string", "array", "null"]},
        "decided": {"type": ["string", "array", "null"]},
        "decided_at": {"type": ["string", "null"], "format": "date-time"},
        "decided_by": {"type": ["string", "null"]},
        "business_plan_ref": {"$ref": "#/definitions/business_plan_ref"}
      }
    },
    "blocker": {
      "type": "object",
      "required": ["id", "description", "affects_tasks", "created_at"],
      "properties": {
        "id": {"type": "string"},
        "description": {"type": "string"},
        "affects_tasks": {
          "type": "array",
          "items": {"type": "string"}
        },
        "created_at": {"type": "string", "format": "date-time"},
        "resolved_at": {"type": ["string", "null"], "format": "date-time"},
        "resolution": {"type": ["string", "null"]}
      }
    }
  }
}

Quick Reference

Meta Object

Field

Type

Required

Description

project

string

Yes

Project name

version

string

Yes

Plan version (semver: X.Y.Z)

schema_version

string

No

Schema version for migrations

created_at

string

Yes

ISO 8601 creation timestamp

updated_at

string

Yes

ISO 8601 last update timestamp

business_plan_path

string

Yes

Path to business plan document

Summary Object

Automatically calculated by pv when saving:

Field

Type

Description

total_phases

integer

Number of phases

total_tasks

integer

Total tasks across all phases

completed_tasks

integer

Number of completed tasks

in_progress_tasks

integer

Currently active tasks

blocked_tasks

integer

Blocked tasks

overall_progress

number

Percentage complete (0-100)

Phase Object

Field

Type

Required

Description

id

string

Yes

Unique phase identifier

name

string

Yes

Phase name

description

string

Yes

Phase description

status

string

Yes

pending, in_progress, completed, blocked, skipped

progress

object

Yes

{completed, total, percentage}

tasks

array

Yes

Array of task objects

Special Phase IDs

  • deferred: Tasks postponed for later consideration

  • 99: Bug tracking phase (convention)

Task Object

Field

Type

Required

Description

id

string

Yes

Task ID format: phase.section.task

title

string

Yes

Task title

status

string

Yes

pending, in_progress, completed, blocked, skipped

agent_type

string/null

Yes

Agent type or null

depends_on

array

Yes

Task IDs this depends on

tracking

object

Yes

Timestamps and metadata

priority

string/null

No

null, low, medium, high

estimated_minutes

integer/null

No

Estimated time

subtasks

array

No

Nested subtask objects

business_plan_ref

object/null

No

Reference to business plan section

Tracking Object

Field

Type

Description

started_at

string/null

ISO 8601 start timestamp

completed_at

string/null

ISO 8601 completion timestamp

time_spent_minutes

integer/null

Actual time spent

notes

string/null

Free-form notes

attempts

integer

Number of attempts (default: 0)

last_error

string/null

Last error message

assigned_agent_id

string/null

Agent instance ID

Valid Statuses

Status

Meaning

pending

Not started

in_progress

Currently being worked on

completed

Finished successfully

blocked

Cannot proceed

skipped

Intentionally skipped

Priority Values

Priority

Meaning

null

No priority set (default)

low

Low priority

medium

Medium priority

high

High priority

Task ID Format

Task IDs follow the pattern phase.section.task:

0.1.1  -> Phase 0, section 1, task 1
1.2.3  -> Phase 1, section 2, task 3
99.1.5 -> Bugs phase, section 1, task 5

Auto-Calculated Fields

When saving a plan (via any edit command), pv automatically:

  1. Updates meta.updated_at to current timestamp

  2. Recalculates progress for each phase

  3. Recalculates the summary totals

  4. Updates phase status based on task completion

Validation

Use pv validate to check your plan.json against the schema:

$ pv validate
plan.json is valid

$ pv validate --json
{"valid": true, "path": "plan.json"}

Invalid plans show the specific error:

$ pv validate
Validation failed for plan.json:
   'status' is a required property
   Path: phases.0.tasks.0

Agent Types

Agent types are flexible strings. Common conventions:

Type

Use Case

general-purpose

Default, general tasks

python-backend-engineer

Python backend development

ui-engineer

Frontend/UI development

github-git-expert

Git operations, PR management

documentation-expert

Documentation tasks

software-architect

Architecture decisions

python-tester

Testing tasks

Any non-empty string is valid, or null for unassigned.

Example Files

The repository includes example plans:

  • examples/simple.json: Basic project with 3 phases, 5 tasks

  • examples/complex.json: Full-featured example with priorities, estimates, decisions

Explore them:

pv -f examples/simple.json
pv -f examples/complex.json summary