- Plan type:
plan - Parent plan:
N/A - Depends on:
N/A - Status:
draft
Status semantics: - draft: Plan is being created or updated and is not final. - approved: Plan is approved but not yet applied in code. - documentation: Code currently exists and matches the plan contract.
Update rule: - When an existing plan is edited, set status to draft until re-approved.
System Intent
- What is being built: Deterministic tooling for
new-plan, resolve-plans, and plan enablement that parses plan contracts and outputs machine-readable create/update/delete implementation scope. - Primary consumer(s): AI agents and developers running plan-first workflows before implementation.
- Boundary (black-box scope only): Parse plan metadata/flows from
docs/plans/*.md, resolve graph dependencies, classify contract diffs, and emit deterministic manifests/checklists without LLM reasoning. - Script ownership: implement scripts under
scripts/plan_tooling/ so planning skills can call a stable CLI instead of re-parsing markdown. - Runtime parser requirement: implement executable parsing code that is run during planning/execution to parse plan files and produce implementation TODOs/manifests; do not rely on ad-hoc LLM-only interpretation.
- Mermaid change-state requirement: implementation scripts must verify that every Mermaid
updated/created/deleted node has matching implemented changes; after verification passes, scripts must normalize Mermaid nodes to unchanged.
Stage Gate Tracker
- [ ] Stage 1 Mermaid approved
- [ ] Stage 2 I/O contracts approved
- [ ] Stage 3 pseudocode/technical details approved or skipped
1. Mermaid Diagram
Reference: .agent/skills/create-mermaid-diagram/SKILL.md
flowchart TD
A[Plan Docs - docs/plans/*.md] -->|parse metadata + flow + types| B[Plan Contract Indexer]
G[Git Base or Snapshot] -->|compare revisions| C[Contract Diff Classifier]
B -->|parent dependency child reverse-dependency edges| D[Related Plan Resolver]
C -->|create update delete deltas| E[Update TODO Builder]
D -->|ordered related plans| E
E -->|CREATE UPDATE DELETE notes| F[Plan Update TODO Manifest]
F -->|file targets + action notes| H[Enable Plans Manifest]
H -->|validate plan-owned vs generated files| I[File Policy Validator]
I -->|deterministic TODO checklist| J[Planning Output for Skills]
classDef unchanged fill:#d3d3d3,stroke:#666,stroke-width:1px;
classDef updated fill:#ffe58a,stroke:#666,stroke-width:1px;
classDef deleted fill:#f4a6a6,stroke:#666,stroke-width:1px;
classDef created fill:#a8e6a3,stroke:#666,stroke-width:1px;
class A,G,B,C,D,E,F,H,I,J created;
Keep this short. Define types in JSON-style blocks and capture each flow with path-level rows. - Flow naming rule: each flow uses this format: - ### Flow: `<flowname>` - - Test files: <path/to/test_file.ext>, ... (or N/A when no automated test is required) - - Core files: <path/to/core_file.ext>, ... - N/A means explicit no-test-required waiver for that flow (not a missing mapping).
Global Types
PlanMetadata {
plan_path: string (repo-relative docs/plans path)
plan_type: "plan" | "sub-plan"
parent_plan: string ("N/A" or docs/plans file name)
depends_on: list[string] (normalized from Depends on / Dependency plans / Depandency plans)
status: "draft" | "approved" | "documentation"
}
PlanChange {
plan_path: string
change_type: "created" | "updated" | "deleted" | "unchanged"
changed_sections: list[string] (metadata, mermaid, io-contracts, pseudocode)
}
FlowContract {
plan_path: string
flow_name: string
test_files: list[string] or "N/A"
core_files: list[string]
path_names: list[string]
}
TypeContract {
plan_path: string
type_name: string
}
ContractPathChange {
plan_path: string
flow_name: string
path_name: string
change_type: "created" | "updated" | "deleted" | "unchanged"
updated_marker: "Y" | ""
test_files: list[string] or "N/A"
core_files: list[string]
}
TypeChange {
plan_path: string
type_name: string
change_type: "created" | "updated" | "deleted" | "unchanged"
}
RelatedPlan {
plan_path: string
discovered_from: string
relation: "seed" | "parent" | "child" | "dependency" | "reverse-dependency"
}
TodoItem {
action: "CREATE" | "UPDATE" | "DELETE"
target_kind: "plan" | "flow" | "type" | "path-row" | "file"
target_id: string
source_plan: string
related_plan: string
required_note: string
file_targets: list[string]
}
ResolvePlansManifest {
seed_plans: list[string]
traversal_order: list[string] (seed, parent-first, dependencies, children, reverse-dependencies)
related_plans: list[RelatedPlan]
checklist_rows: list[{
plan_path: string
discovered_from: string
action: "review"
status: "pending" | "updated" | "no-change"
}]
}
PlanUpdateTodoManifest {
seed_plans: list[string]
related_plans: list[string]
flow_changes: list[ContractPathChange]
type_changes: list[TypeChange]
todo_items: list[TodoItem]
todo_markdown_lines: list[string] (one line per item: "[ACTION] <target_kind> <target_id> - <required_note>")
blocking_errors: list[string]
}
MermaidNodeChangeState {
plan_path: string
node_id: string
state: "unchanged" | "updated" | "created" | "deleted"
referenced_targets: list[string]
}
PlanImplementationVerificationManifest {
plan_path: string
mermaid_nodes: list[MermaidNodeChangeState]
checked_targets: list[string]
unresolved_change_nodes: list[string]
missing_targets: list[string]
blocking_errors: list[string]
}
EnablePlansManifest {
plan_items: list[string]
file_items: list[{
plan_path: string
file_path: string
required_reason: string
}]
delete_items: list[{
plan_path: string
target_path: string
reason: string
}]
todo_items: list[TodoItem]
file_policy_items: list[{
file_path: string
policy: "plan-owned" | "generated"
generated_pattern: "<filename>.generated.<extension>" | ""
}]
blocking_errors: list[string]
}
API Reference
plan-tool new-plan --plan <docs/plans/*.md> [--base <git-ref>]
-> PlanMetadata + ContractPathChange summary
plan-tool resolve-plans --seed <docs/plans/a.md> [--seed <docs/plans/b.md> ...] [--base <git-ref>]
-> ResolvePlansManifest + PlanUpdateTodoManifest
plan-tool generate-update-todos --seed <docs/plans/a.md> [--base <git-ref>] [--out-json <path>] [--out-md <path>]
-> PlanUpdateTodoManifest
plan-tool enable-plans --seed <docs/plans/a.md> [--base <git-ref>] [--mode approved|documentation] [--todo <manifest.json>]
-> EnablePlansManifest
plan-tool validate-plan-file-policy --todo <manifest.json>
-> file policy report + blocking errors
plan-tool verify-plan-implementation --plan <docs/plans/*.md> [--base <git-ref>] [--todo <manifest.json>]
-> PlanImplementationVerificationManifest
plan-tool normalize-mermaid-state --plan <docs/plans/*.md> --require-clean-implementation
-> plan file updated with Mermaid class nodes set to unchanged
Skill Integration Contract
update-plan skill stage (resolve plans):
1) plan-tool resolve-plans --seed <updated-plan> --base <git-ref>
2) plan-tool generate-update-todos --seed <updated-plan> --base <git-ref> --out-json <tmp/todos.json> --out-md <tmp/todos.md>
3) planning skill consumes todos.json/todos.md and executes CREATE/UPDATE/DELETE notes in order.
reconcile-plans skill stage:
1) use related_plans from ResolvePlansManifest as deterministic review queue.
2) if any reconciled plan changes, re-run generate-update-todos for that plan before implementation.
execute-plan skill stage:
1) consume todo_items directly; do not infer missing work from prose.
2) call validate-plan-file-policy before write/commit to enforce exact naming and .generated policy.
3) run parser + manifest commands as the source of truth for what gets implemented.
4) run verify-plan-implementation to prove Mermaid change nodes are fully implemented.
5) run normalize-mermaid-state only after verification passes so Mermaid shows no-change.
6) set plan status to `documentation` only after Mermaid normalization succeeds.
required implementation output files for this plan:
1) .agent/skills/update-plan/SKILL.md
2) .agent/skills/reconcile-plans/SKILL.md
3) .agent/skills/execute-plan/SKILL.md
4) scripts/plan_tooling/* (parser/manifest code)
- Test files:
main/server/tests/unit/test_plan_tooling_parser.py - Core files:
scripts/plan_tooling/plan_parser.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
plan-metadata-parse.success | plan markdown with Plan Metadata block | PlanMetadata | happy path | parser extracts Plan type, Parent plan, Depends on, and Status | Y |
plan-metadata-parse.legacy-dependency-keys | plan markdown with Dependency plans or Depandency plans label | PlanMetadata depends_on normalized | subpath | accept legacy key spellings deterministically | Y |
plan-metadata-parse.invalid-metadata | plan missing required metadata key | blocking error with exact missing field | error | required before any resolve/enable operation | Y |
Flow: plan-contract-index
- Test files:
main/server/tests/unit/test_plan_tooling_contract_index.py - Core files:
scripts/plan_tooling/contract_index.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
plan-contract-index.flows-and-types | plan markdown with Global Types and Flow blocks | FlowContract + TypeContract index | happy path | all flow names and type names are captured verbatim for exact-match validation | Y |
plan-contract-index.missing-flow-test-line | flow heading without Test files line | blocking error with plan path + flow name | error | rejects implicit test mappings | Y |
plan-contract-index.missing-flow-core-line | flow heading without Core files line | blocking error with plan path + flow name | error | every flow must define implementation target files | Y |
Flow: plan-change-classification
- Test files:
main/server/tests/unit/test_plan_tooling_diff.py - Core files:
scripts/plan_tooling/plan_diff.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
plan-change-classification.created-plan | new plan path exists in workspace but not in base | PlanChange change_type=created | happy path | generated for new-plan command seeds | Y |
plan-change-classification.updated-plan | plan content differs from base | PlanChange change_type=updated changed_sections populated | happy path | section-aware diff drives deterministic review scope | Y |
plan-change-classification.deleted-plan | plan path exists in base but not workspace | PlanChange change_type=deleted | subpath | emitted so enable manifest can include delete work | Y |
plan-change-classification.unchanged-plan | plan content equal to base | PlanChange change_type=unchanged | subpath | unchanged plans can still appear in dependency traversal as no-change | Y |
plan-change-classification.type-and-flow-deltas | old + new contract indexes | TypeChange + ContractPathChange with created/updated/deleted | happy path | tracks new flows, deleted flows, and changed types deterministically | Y |
- Test files:
main/server/tests/unit/test_plan_tooling_resolve.py - Core files:
scripts/plan_tooling/plan_graph.py, scripts/plan_tooling/resolve_plans.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
resolve-plans-related-graph.parent-first | seed plan list with valid metadata | ResolvePlansManifest traversal_order starts with seed then parent before dependencies | happy path | parent contract is always reviewed before dependency fan-out | Y |
resolve-plans-related-graph.reverse-links | all plan metadata scanned | children + reverse-dependencies discovered | happy path | pulls related plans that reference the seed so no impacted plan is skipped | Y |
resolve-plans-related-graph.cycle-handled | relationship cycle across plans | ResolvePlansManifest produced without infinite loop | error | cycle recorded as warning and traversal continues | Y |
Flow: resolve-plans-todo-generation
- Test files:
main/server/tests/unit/test_plan_tooling_todo_manifest.py - Core files:
scripts/plan_tooling/todo_manifest.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
resolve-plans-todo-generation.create-update-delete | seed plan changes + related plans + flow/type deltas | PlanUpdateTodoManifest todo_items with action CREATE/UPDATE/DELETE | happy path | emits deterministic TODO notes for every impacted plan/flow/type/path row | Y |
resolve-plans-todo-generation.no-llm-gap | same input snapshot run multiple times | stable sorted TODO output | happy path | deterministic sort key prevents LLM omissions or ordering drift | Y |
resolve-plans-todo-generation.action-note-format | todo_items with required_note | todo_markdown_lines in exact format [ACTION] target_kind target_id - note | subpath | planning skills can read/update TODO files without parsing markdown sections | Y |
resolve-plans-todo-generation.missing-related-plan | diff references plan not present in graph | blocking error with seed + missing plan path | error | prevents partial TODO manifests | Y |
Flow: planning-skill-handoff
- Test files:
main/server/tests/unit/test_plan_tooling_skill_handoff.py - Core files:
scripts/plan_tooling/skill_handoff.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
planning-skill-handoff.write-json-and-md | PlanUpdateTodoManifest + output paths | todos.json + todos.md written deterministically | happy path | planning skills receive one machine-readable artifact and one human-readable checklist | Y |
planning-skill-handoff.strict-action-order | unordered todo_items | sorted output by (related_plan, target_kind, target_id, action) | happy path | stable order prevents checklist churn and missed updates | Y |
planning-skill-handoff.unknown-action | todo item action outside CREATE/UPDATE/DELETE | blocking error with target_id + action | error | prevents ambiguous TODO execution | Y |
Flow: planning-skill-trigger-enforcement
- Test files:
main/server/tests/unit/test_plan_tooling_skill_contracts.py - Core files:
scripts/plan_tooling/skill_contracts.py, .agent/skills/update-plan/SKILL.md, .agent/skills/reconcile-plans/SKILL.md, .agent/skills/execute-plan/SKILL.md
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
planning-skill-trigger-enforcement.required-files | implementation diff for deterministic-plan-tooling scope | blocking error if any required skill file is not updated | error | guarantees skill wiring changes are included with parser/tooling implementation | Y |
planning-skill-trigger-enforcement.update-plan-hooks | updated update-plan skill | explicit command hooks for resolve-plans and generate-update-todos | happy path | ensure resolve stage always triggers deterministic TODO generation | Y |
planning-skill-trigger-enforcement.reconcile-hooks | updated reconcile-plans skill | explicit command hook using ResolvePlansManifest related_plans queue | happy path | ensures related plans are discovered/reviewed from tooling output, not manual inference | Y |
planning-skill-trigger-enforcement.execute-hooks | updated execute-plan skill | explicit command hook for validate-plan-file-policy before writes | happy path | prevents implementation drift outside plan contracts | Y |
Flow: plan-file-policy-validation
- Test files:
main/server/tests/unit/test_plan_tooling_file_policy.py - Core files:
scripts/plan_tooling/file_policy.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
plan-file-policy-validation.plan-owned-exact-match | todo item targets non-generated file | all symbols in file match plan-defined flow/type names exactly | happy path | non-generated files are contract-owned and cannot include undocumented symbols | Y |
plan-file-policy-validation.generated-allowed | todo item targets <filename>.generated.<extension> | file marked policy=generated | subpath | generated files may contain helper code not explicitly modeled in plans | Y |
plan-file-policy-validation.non-generated-extra-symbol | non-generated file contains symbol not in plan contracts | blocking error with file path + symbol | error | enforces strict plan-to-code contract boundaries | Y |
Flow: mermaid-change-implementation-validation
- Test files:
main/server/tests/unit/test_plan_tooling_mermaid_validation.py - Core files:
scripts/plan_tooling/mermaid_validation.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
mermaid-change-implementation-validation.pass | plan with Mermaid nodes marked updated/created/deleted + implemented targets present | PlanImplementationVerificationManifest with unresolved_change_nodes=[] | happy path | proves each Mermaid change marker has corresponding implemented contract/file changes | Y |
mermaid-change-implementation-validation.missing-target | Mermaid changed node references target file/symbol not implemented | blocking error with node_id + missing target | error | prevents claiming completion when implementation is incomplete | Y |
mermaid-change-implementation-validation.status-doc-with-changes | plan status=documentation while Mermaid has non-unchanged nodes | blocking error requiring normalize-mermaid-state | error | documentation status cannot coexist with pending Mermaid change markers | Y |
Flow: mermaid-change-state-normalization
- Test files:
main/server/tests/unit/test_plan_tooling_mermaid_normalize.py - Core files:
scripts/plan_tooling/mermaid_normalize.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
mermaid-change-state-normalization.clean-to-unchanged | verified plan with Mermaid changed nodes and no blocking errors | plan Mermaid class lines rewritten so all nodes are unchanged | happy path | deterministic cleanup after implementation completion | Y |
mermaid-change-state-normalization.blocked-on-unresolved | verification manifest with unresolved_change_nodes or missing_targets | blocking error and no Mermaid mutation | error | guarantees no false no-change state | Y |
mermaid-change-state-normalization.idempotent | plan already all unchanged | no diff output | subpath | safe to run at end of every execute-plan flow | Y |
Flow: enable-plans-scope
- Test files:
main/server/tests/unit/test_plan_tooling_enable_scope.py - Core files:
scripts/plan_tooling/enable_scope.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
enable-plans-scope.updated-rows-to-file-items | changed plans with contract rows marked updated=Y | EnablePlansManifest file_items for each flow core file | happy path | this is the deterministic implementation scope source | Y |
enable-plans-scope.deleted-path-row | ContractPathChange change_type=deleted | EnablePlansManifest delete_items populated | subpath | delete work is explicit, never inferred by LLM | Y |
enable-plans-scope.todo-manifest-ingest | PlanUpdateTodoManifest todo_items | EnablePlansManifest.todo_items preserved with action notes | happy path | planning skills consume TODOs directly without re-parsing markdown | Y |
enable-plans-scope.missing-test-mapping | flow heading missing test files and not N/A | blocking error with plan path + flow name | error | prevents execution on incomplete plan contracts | Y |
Flow: enable-plans-gates
- Test files:
main/server/tests/unit/test_plan_tooling_enable_gates.py - Core files:
scripts/plan_tooling/enable_plans.py
Type Definitions
FlowInput = see Global Types
FlowOutput = see path table contracts
Paths
| path-name | input | output/expected state change | path-type | notes | updated |
enable-plans-gates.approved-mode | plans with status=approved and completed stage gates | EnablePlansManifest with no gate errors | happy path | allows implementation mode with deterministic checklist | Y |
enable-plans-gates.documentation-mode | plans with status=documentation and no updated=Y rows | EnablePlansManifest with no gate errors | happy path | supports verification-only reruns | Y |
enable-plans-gates.blocked-status-or-gates | draft status or unchecked stage gate | blocking error listing violating plans | error | enforce planning gate before execution | Y |
3. Pseudocode / Technical Details for Critical Flows (Optional)
- Flow name:
resolve-and-generate-update-todos parse changed plans and metadata from docs/plans
index all flow contracts and global type names exactly as written in plans
classify plan, flow, path-row, and type deltas against base revision
resolve related plans in deterministic order: seed, parent, dependencies, children, reverse-dependencies
for each delta emit TodoItem action CREATE/UPDATE/DELETE with required_note
map todo items to file targets from each flow Core files list
verify each Mermaid node marked updated/created/deleted maps to implemented targets
block completion when any Mermaid change node is unresolved
after successful verification rewrite Mermaid class states to unchanged
mark file policy as generated only when file name matches <filename>.generated.<extension>
enforce required skill files are updated and contain command hooks for deterministic plan-tool invocations
validate non-generated files do not contain undocumented symbols
emit ResolvePlansManifest + PlanUpdateTodoManifest + EnablePlansManifest
exit non-zero when any blocking errors exist
- Implementation notes:
- Output must be stable JSON and sorted by
(related_plan, target_kind, target_id, action) so planning skills can consume deterministically. - Parser must fail fast with exact
path:line diagnostics for malformed metadata, flow headings, type blocks, or missing test/core file mappings. - All user-defined names in plans are exact-match identifiers; no alias expansion is allowed for flow names or type names.
- Non-generated files must only contain plan-defined contract symbols. Any extra symbol is a blocking error.
- Generated helper outputs must follow
<filename>.generated.<extension> to allow deterministic overwrite/update by tooling.
After all stages are approved, apply .agent/skills/reconcile-plans/SKILL.md to propagate contract updates across linked plans.