@davidorex/pi-jit-agents 0.14.6 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/README.md +2 -2
- package/dist/agent-spec.d.ts.map +1 -1
- package/dist/agent-spec.js +69 -5
- package/dist/agent-spec.js.map +1 -1
- package/dist/budget-enforcer.d.ts +43 -0
- package/dist/budget-enforcer.d.ts.map +1 -0
- package/dist/budget-enforcer.js +172 -0
- package/dist/budget-enforcer.js.map +1 -0
- package/dist/compile.d.ts +39 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +363 -24
- package/dist/compile.js.map +1 -1
- package/dist/dispatch-inline.d.ts +25 -0
- package/dist/dispatch-inline.d.ts.map +1 -0
- package/dist/dispatch-inline.js +41 -0
- package/dist/dispatch-inline.js.map +1 -0
- package/dist/field-path.d.ts +32 -0
- package/dist/field-path.d.ts.map +1 -0
- package/dist/field-path.js +48 -0
- package/dist/field-path.js.map +1 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/jit-runtime.d.ts +14 -3
- package/dist/jit-runtime.d.ts.map +1 -1
- package/dist/jit-runtime.js +41 -5
- package/dist/jit-runtime.js.map +1 -1
- package/dist/markers.d.ts +28 -0
- package/dist/markers.d.ts.map +1 -0
- package/dist/markers.js +36 -0
- package/dist/markers.js.map +1 -0
- package/dist/renderer-registry.d.ts +60 -0
- package/dist/renderer-registry.d.ts.map +1 -0
- package/dist/renderer-registry.js +141 -0
- package/dist/renderer-registry.js.map +1 -0
- package/dist/template.d.ts +15 -0
- package/dist/template.d.ts.map +1 -1
- package/dist/template.js +29 -3
- package/dist/template.js.map +1 -1
- package/dist/trace-redactor.d.ts +1 -1
- package/dist/trace-redactor.js +1 -1
- package/dist/trace-writer.js +2 -2
- package/dist/types.d.ts +86 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -4
- package/schemas/agent-trace.schema.json +30 -2
- package/templates/analyzers/base-analyzer.md +9 -0
- package/templates/analyzers/patterns-task.md +11 -0
- package/templates/analyzers/patterns.md +15 -0
- package/templates/analyzers/quality-task.md +11 -0
- package/templates/analyzers/quality.md +15 -0
- package/templates/analyzers/structure-task.md +17 -0
- package/templates/analyzers/structure.md +15 -0
- package/templates/architecture-designer/task.md +117 -0
- package/templates/architecture-inferrer/task.md +61 -0
- package/templates/audit-finding-verifier/task.md +59 -0
- package/templates/audit-fixer/task.md +67 -0
- package/templates/audit-results-router/task.md +37 -0
- package/templates/decomposer/task.md +56 -0
- package/templates/explorer/system.md +3 -0
- package/templates/explorer/task.md +9 -0
- package/templates/gap-identifier/task.md +103 -0
- package/templates/gap-resolution-assessor/task.md +48 -0
- package/templates/handoff-writer/task.md +101 -0
- package/templates/investigator/task.md +30 -0
- package/templates/items/architecture.md +33 -0
- package/templates/items/conformance.md +26 -0
- package/templates/items/conventions.md +19 -0
- package/templates/items/decisions.md +47 -0
- package/templates/items/domain.md +21 -0
- package/templates/items/features.md +63 -0
- package/templates/items/framework-gaps.md +43 -0
- package/templates/items/issues.md +21 -0
- package/templates/items/layer-plans.md +50 -0
- package/templates/items/project.md +48 -0
- package/templates/items/requirements.md +20 -0
- package/templates/items/research.md +57 -0
- package/templates/items/spec-reviews.md +51 -0
- package/templates/items/tasks.md +29 -0
- package/templates/phase-author/task.md +82 -0
- package/templates/plan-creator/task.md +143 -0
- package/templates/plan-decomposer/task.md +46 -0
- package/templates/project-definer/task.md +67 -0
- package/templates/project-inferrer/task.md +56 -0
- package/templates/requirements-gatherer/task.md +90 -0
- package/templates/researcher/task.md +26 -0
- package/templates/shared/macros.md +169 -0
- package/templates/shared/render-helpers.md +106 -0
- package/templates/spec-implementer/task.md +53 -0
- package/templates/synthesizer/system.md +3 -0
- package/templates/synthesizer/task.md +38 -0
- package/templates/task-verifier/task.md +44 -0
- package/templates/task-worker/task.md +52 -0
- package/templates/verifier/task.md +57 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `features` block.
|
|
3
|
+
|
|
4
|
+
Block schema: .project/schemas/features.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
+
|
|
6
|
+
Cross-block reference recursion (dependencies, gates, blocks_resolved,
|
|
7
|
+
decisions) is delegated to shared/render-helpers.md — see that file for
|
|
8
|
+
the depth contract, ambient globals, and empty-array convention.
|
|
9
|
+
|
|
10
|
+
Nested embedded structures:
|
|
11
|
+
Each feature carries nested `stories[]` (with embedded `tasks[]`) and
|
|
12
|
+
`findings[]` (scoped-finding shape). These are NOT separate block kinds
|
|
13
|
+
— they are sub-shapes on the feature schema and have no per-item macro
|
|
14
|
+
of their own. They are rendered inline as sub-lists under the feature
|
|
15
|
+
body. Story-level `depends_on`/`gates` are rendered as bare-ID lists
|
|
16
|
+
(story IDs are scoped to the feature, not in the global index) and stay
|
|
17
|
+
inline because they use a deeper indent (4 spaces) than the helper
|
|
18
|
+
convention assumes.
|
|
19
|
+
-#}
|
|
20
|
+
{% from "shared/render-helpers.md" import render_id_list_block, render_optional_scalar %}
|
|
21
|
+
|
|
22
|
+
{% macro render_feature(feat, depth=0) %}
|
|
23
|
+
ID: {{ feat.id }}
|
|
24
|
+
Title: {{ feat.title }}
|
|
25
|
+
Status: {{ feat.status }}
|
|
26
|
+
Layer: {{ feat.layer }}
|
|
27
|
+
Created by: {{ feat.created_by }}
|
|
28
|
+
Created at: {{ feat.created_at }}
|
|
29
|
+
{{ render_optional_scalar("Modified by", feat.modified_by) }}{{ render_optional_scalar("Modified at", feat.modified_at) }}{{ render_optional_scalar("Approved by", feat.approved_by) }}{{ render_optional_scalar("Approved at", feat.approved_at) }}
|
|
30
|
+
Description:
|
|
31
|
+
{{ enforceBudget(feat.description, "features", "features.items.description") }}
|
|
32
|
+
|
|
33
|
+
{% if feat.motivation %}Motivation:
|
|
34
|
+
{{ enforceBudget(feat.motivation, "features", "features.items.motivation") }}
|
|
35
|
+
|
|
36
|
+
{% endif %}Acceptance criteria:
|
|
37
|
+
{% if feat.acceptance_criteria and feat.acceptance_criteria | length > 0 %}{% for ac in feat.acceptance_criteria %} - {{ ac }}
|
|
38
|
+
{% endfor %}{% else %} (none)
|
|
39
|
+
{% endif %}{{ render_id_list_block("Dependencies", feat.dependencies, depth) }}{{ render_id_list_block("Gates", feat.gates, depth) }}{{ render_id_list_block("Blocks resolved", feat.blocks_resolved, depth) }}{{ render_id_list_block("Decisions", feat.decisions, depth) }}Stories:
|
|
40
|
+
{% if feat.stories and feat.stories | length > 0 %}{% for s in feat.stories %} - {{ s.id }} [{{ s.status }}] {{ s.title }}
|
|
41
|
+
{% if s.description %} Description: {{ enforceBudget(s.description, "features", "features.items.stories.items.description") }}
|
|
42
|
+
{% endif %}{% if s.acceptance_criteria is defined %} Acceptance criteria: {% if s.acceptance_criteria | length > 0 %}{% for ac in s.acceptance_criteria %}{{ ac }}{% if not loop.last %}; {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
43
|
+
{% endif %}{% if s.depends_on is defined %} Depends on: {% if s.depends_on | length > 0 %}{% for dep in s.depends_on %}{{ dep }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
44
|
+
{% endif %}{% if s.gates is defined %} Gates: {% if s.gates | length > 0 %}{% for g in s.gates %}{{ g }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
45
|
+
{% endif %} Tasks:
|
|
46
|
+
{% if s.tasks and s.tasks | length > 0 %}{% for t in s.tasks %} - {{ t.id }} [{{ t.status }}] {{ t.title }}
|
|
47
|
+
{% if t.description %} Description: {{ t.description }}
|
|
48
|
+
{% endif %}{% if t.files is defined %} Files: {% if t.files | length > 0 %}{% for f in t.files %}{{ f }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
49
|
+
{% endif %}{% if t.acceptance %} Acceptance: {{ t.acceptance }}
|
|
50
|
+
{% endif %}{% if t.depends_on is defined %} Depends on: {% if t.depends_on | length > 0 %}{% for dep in t.depends_on %}{{ dep }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
51
|
+
{% endif %}{% if t.assigned_to %} Assigned to: {{ t.assigned_to }}
|
|
52
|
+
{% endif %}{% endfor %}{% else %} (none)
|
|
53
|
+
{% endif %}{% endfor %}{% else %} (none)
|
|
54
|
+
{% endif %}Findings:
|
|
55
|
+
{% if feat.findings and feat.findings | length > 0 %}{% for f in feat.findings %} - {{ f.id }} [{{ f.severity }}/{{ f.state }}] reporter={{ f.reporter }} at={{ f.created_at }}
|
|
56
|
+
Description: {{ enforceBudget(f.description, "features", "features.items.findings.items.description") }}
|
|
57
|
+
{% if f.evidence %} Evidence: {{ f.evidence }}
|
|
58
|
+
{% endif %}{% if f.category %} Category: {{ f.category }}
|
|
59
|
+
{% endif %}{% if f.resolution %} Resolution: {{ f.resolution }}
|
|
60
|
+
{% endif %}{% if f.resolved_by %} Resolved by: {{ f.resolved_by }}
|
|
61
|
+
{% endif %}{% if f.resolved_at %} Resolved at: {{ f.resolved_at }}
|
|
62
|
+
{% endif %}{% endfor %}{% else %} (none)
|
|
63
|
+
{% endif %}{% endmacro %}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `framework-gaps` block.
|
|
3
|
+
|
|
4
|
+
Block schema: .project/schemas/framework-gaps.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
+
|
|
6
|
+
Cross-block reference recursion (related_features, related_decisions,
|
|
7
|
+
related_issues) is delegated to shared/render-helpers.md — see that file
|
|
8
|
+
for the depth contract, ambient globals, and empty-array convention.
|
|
9
|
+
|
|
10
|
+
Naming note:
|
|
11
|
+
The canonical macro name is `render_framework_gap`. The legacy
|
|
12
|
+
`render_gap` macro lives in templates/shared/macros.md and retires
|
|
13
|
+
under Plan 8 (parallel). Plan 7 deliberately does NOT author
|
|
14
|
+
`render_gap` here.
|
|
15
|
+
|
|
16
|
+
Evidence array:
|
|
17
|
+
Each gap carries an embedded `evidence[]` of {file, lines, reference}
|
|
18
|
+
triples. These are file pointers, NOT block IDs — rendered inline as
|
|
19
|
+
sub-list, never recursed.
|
|
20
|
+
-#}
|
|
21
|
+
{% from "shared/render-helpers.md" import render_id_list_block, render_optional_scalar %}
|
|
22
|
+
|
|
23
|
+
{% macro render_framework_gap(gap, depth=0) %}
|
|
24
|
+
ID: {{ gap.id }}
|
|
25
|
+
Title: {{ gap.title }}
|
|
26
|
+
Status: {{ gap.status }}
|
|
27
|
+
Package: {{ gap.package }}
|
|
28
|
+
Created by: {{ gap.created_by }}
|
|
29
|
+
Created at: {{ gap.created_at }}
|
|
30
|
+
{{ render_optional_scalar("Priority", gap.priority) }}{{ render_optional_scalar("Layer", gap.layer) }}{{ render_optional_scalar("Canonical vocabulary", gap.canonical_vocabulary) }}{{ render_optional_scalar("Closed by", gap.closed_by) }}{{ render_optional_scalar("Closed at", gap.closed_at) }}
|
|
31
|
+
Description:
|
|
32
|
+
{{ enforceBudget(gap.description, "framework-gaps", "gaps.items.description") }}
|
|
33
|
+
|
|
34
|
+
Impact:
|
|
35
|
+
{{ enforceBudget(gap.impact, "framework-gaps", "gaps.items.impact") }}
|
|
36
|
+
|
|
37
|
+
Proposed resolution:
|
|
38
|
+
{{ enforceBudget(gap.proposed_resolution, "framework-gaps", "gaps.items.proposed_resolution") }}
|
|
39
|
+
|
|
40
|
+
Evidence:
|
|
41
|
+
{% if gap.evidence and gap.evidence | length > 0 %}{% for e in gap.evidence %} - {{ e.file }}{% if e.lines %}:{{ e.lines }}{% endif %} — {{ enforceBudget(e.reference, "framework-gaps", "gaps.items.evidence.items.reference") }}
|
|
42
|
+
{% endfor %}{% else %} (none)
|
|
43
|
+
{% endif %}{{ render_id_list_block("Related features", gap.related_features, depth) }}{{ render_id_list_block("Related decisions", gap.related_decisions, depth) }}{{ render_id_list_block("Related issues", gap.related_issues, depth) }}{% endmacro %}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `issues` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
+
|
|
4
|
+
Block schema: .project/schemas/issues.schema.json. Each item is one issue
|
|
5
|
+
inside data.issues[]. Required: id (^issue-\d{3}$), title, body, location,
|
|
6
|
+
status, category, priority, package. Optional: source, resolved_by.
|
|
7
|
+
|
|
8
|
+
No cross-block references in current schema — resolved_by is a free-form
|
|
9
|
+
commit reference, not a project-block ID. Depth parameter accepted for
|
|
10
|
+
renderer-registry shape-uniformity; reserved for future schema additions
|
|
11
|
+
(e.g., resolved_by_pr or related_decisions[]).
|
|
12
|
+
-#}
|
|
13
|
+
|
|
14
|
+
{% macro render_issue(i, depth=0) %}
|
|
15
|
+
{% if i %}- **{{ i.id }}** [{{ i.priority }}, {{ i.status }}]: {{ i.title }}
|
|
16
|
+
{{ enforceBudget(i.body, "issues", "issues.items.body") }}{% if i.location %} — {{ i.location }}{% endif %}{% if i.package %} ({{ i.package }}){% endif %}
|
|
17
|
+
{% if i.category %} Category: {{ i.category }}
|
|
18
|
+
{% endif %}{% if i.source %} Source: {{ i.source }}
|
|
19
|
+
{% endif %}{% if i.resolved_by %} Resolved by: {{ i.resolved_by }}
|
|
20
|
+
{% endif %}{% endif %}
|
|
21
|
+
{% endmacro %}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `layer-plans` block.
|
|
3
|
+
|
|
4
|
+
Block schema: .project/schemas/layer-plans.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
+
|
|
6
|
+
Cross-block reference recursion (related_gaps, related_features,
|
|
7
|
+
related_decisions) is delegated to shared/render-helpers.md — see that
|
|
8
|
+
file for the depth contract, ambient globals, and empty-array convention.
|
|
9
|
+
|
|
10
|
+
Nested embedded structures:
|
|
11
|
+
Each plan carries `layers[]` (each with current_blocks/target_blocks
|
|
12
|
+
sub-arrays) and `migration_phases[]`. These are NOT separate block kinds
|
|
13
|
+
— they are sub-shapes on the plan schema and rendered inline. Phase
|
|
14
|
+
`depends_on` references are scoped to phase IDs within the same plan and
|
|
15
|
+
rendered as bare-ID lists (no recursion).
|
|
16
|
+
-#}
|
|
17
|
+
{% from "shared/render-helpers.md" import render_id_list_block %}
|
|
18
|
+
|
|
19
|
+
{% macro render_layer_plan(plan, depth=0) %}
|
|
20
|
+
ID: {{ plan.id }}
|
|
21
|
+
Title: {{ plan.title }}
|
|
22
|
+
Status: {{ plan.status }}
|
|
23
|
+
Model: {{ plan.model }}
|
|
24
|
+
Created by: {{ plan.created_by }}
|
|
25
|
+
Created at: {{ plan.created_at }}
|
|
26
|
+
{% if plan.description %}
|
|
27
|
+
Description:
|
|
28
|
+
{{ enforceBudget(plan.description, "layer-plans", "plans.items.description") }}
|
|
29
|
+
|
|
30
|
+
{% endif %}Layers:
|
|
31
|
+
{% if plan.layers and plan.layers | length > 0 %}{% for l in plan.layers %} - {{ l.id }}: {{ l.name }}
|
|
32
|
+
Purpose: {{ enforceBudget(l.purpose, "layer-plans", "plans.items.layers.items.purpose") }}
|
|
33
|
+
{% if l.canonical_vocabulary %} Canonical vocabulary: {{ l.canonical_vocabulary }}
|
|
34
|
+
{% endif %}{% if l.lifetime %} Lifetime: {{ l.lifetime }}
|
|
35
|
+
{% endif %}{% if l.ownership_principle %} Ownership principle: {{ enforceBudget(l.ownership_principle, "layer-plans", "plans.items.layers.items.ownership_principle") }}
|
|
36
|
+
{% endif %} Current blocks: {% if l.current_blocks | length > 0 %}{% for cb in l.current_blocks %}{{ cb }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
37
|
+
Target blocks:
|
|
38
|
+
{% if l.target_blocks and l.target_blocks | length > 0 %}{% for tb in l.target_blocks %} - {{ tb.name }} (shape: {{ tb.shape }}){% if tb.notes %} — {{ tb.notes }}{% endif %}
|
|
39
|
+
{% endfor %}{% else %} (none)
|
|
40
|
+
{% endif %}{% endfor %}{% else %} (none)
|
|
41
|
+
{% endif %}Migration phases:
|
|
42
|
+
{% if plan.migration_phases and plan.migration_phases | length > 0 %}{% for p in plan.migration_phases %} - {{ p.id }}: {{ p.name }}{% if p.status %} [{{ p.status }}]{% endif %}
|
|
43
|
+
Description: {{ enforceBudget(p.description, "layer-plans", "plans.items.migration_phases.items.description") }}
|
|
44
|
+
Depends on: {% if p.depends_on | length > 0 %}{% for dep in p.depends_on %}{{ dep }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
45
|
+
Exit criteria:
|
|
46
|
+
{% if p.exit_criteria | length > 0 %}{% for ec in p.exit_criteria %} - {{ enforceBudget(ec, "layer-plans", "plans.items.migration_phases.items.exit_criteria.items") }}
|
|
47
|
+
{% endfor %}{% else %} (none)
|
|
48
|
+
{% endif %}{% if p.produces is defined %} Produces: {% if p.produces | length > 0 %}{% for pr in p.produces %}{{ pr }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
49
|
+
{% endif %}{% endfor %}{% else %} (none)
|
|
50
|
+
{% endif %}{{ render_id_list_block("Related gaps", plan.related_gaps, depth) }}{{ render_id_list_block("Related features", plan.related_features, depth) }}{{ render_id_list_block("Related decisions", plan.related_decisions, depth) }}{% endmacro %}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `project` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
+
|
|
4
|
+
Singleton kind: the project block holds one record per repository (no
|
|
5
|
+
homogeneous items[] array). The "per-item" rendering thus operates on the
|
|
6
|
+
whole block payload as a single record. The whole-block delegator in
|
|
7
|
+
shared/macros.md passes its data argument straight through.
|
|
8
|
+
|
|
9
|
+
No cross-block references — depth parameter accepted for shape-uniformity
|
|
10
|
+
with other per-item macros; no helpers from shared/render-helpers.md are
|
|
11
|
+
needed at present.
|
|
12
|
+
|
|
13
|
+
Empty-array convention:
|
|
14
|
+
Optional list/object fields render their label only when populated. The
|
|
15
|
+
project schema makes `name`, `description`, and `core_value` required and
|
|
16
|
+
the rest optional; bare-required output is the predictable shape for
|
|
17
|
+
minimal records.
|
|
18
|
+
-#}
|
|
19
|
+
|
|
20
|
+
{% macro render_project_item(p, depth=0) %}
|
|
21
|
+
{% if p %}
|
|
22
|
+
## Project
|
|
23
|
+
**{{ p.name }}** — {{ enforceBudget(p.description, "project", "description") }}
|
|
24
|
+
{% if p.core_value %}Core value: {{ enforceBudget(p.core_value, "project", "core_value") }}{% endif %}
|
|
25
|
+
{% if p.vision %}
|
|
26
|
+
Vision: {{ enforceBudget(p.vision, "project", "vision") }}{% endif %}
|
|
27
|
+
{% if p.status %}Status: {{ p.status }}{% endif %}
|
|
28
|
+
{% if p.target_users %}
|
|
29
|
+
Target users: {{ p.target_users | join(", ") }}{% endif %}
|
|
30
|
+
{% if p.constraints %}
|
|
31
|
+
### Constraints
|
|
32
|
+
{% for c in p.constraints %}- [{{ c.type }}] {{ enforceBudget(c.description, "project", "constraints.items.description") }}
|
|
33
|
+
{% endfor %}{% endif %}
|
|
34
|
+
{% if p.scope_boundaries %}
|
|
35
|
+
### Scope
|
|
36
|
+
**In:** {% for s in p.scope_boundaries.in %}{{ s }}{% if not loop.last %}, {% endif %}{% endfor %}
|
|
37
|
+
|
|
38
|
+
**Out:** {% for s in p.scope_boundaries.out %}{{ s }}{% if not loop.last %}, {% endif %}{% endfor %}
|
|
39
|
+
{% endif %}
|
|
40
|
+
{% if p.goals %}
|
|
41
|
+
### Goals
|
|
42
|
+
{% for g in p.goals %}- **{{ g.id }}**: {{ enforceBudget(g.description, "project", "goals.items.description") }}{% if g.success_criteria %} — criteria: {% for sc in g.success_criteria %}{{ enforceBudget(sc, "project", "goals.items.success_criteria.items") }}{% if not loop.last %}; {% endif %}{% endfor %}{% endif %}
|
|
43
|
+
{% endfor %}{% endif %}
|
|
44
|
+
{% if p.repository %}Repository: {{ p.repository }}
|
|
45
|
+
{% endif %}{% if p.stack %}Stack: {{ p.stack | join(", ") }}
|
|
46
|
+
{% endif %}
|
|
47
|
+
{% endif %}
|
|
48
|
+
{% endmacro %}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `requirements` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
+
|
|
4
|
+
Block schema: .project/schemas/requirements.schema.json. Each item is one
|
|
5
|
+
requirement inside data.requirements[]. Required: id (^REQ-\d{3,}$),
|
|
6
|
+
description, type, status, priority. Optional: acceptance_criteria,
|
|
7
|
+
source, traces_to (phase/task IDs), depends_on (other requirement IDs).
|
|
8
|
+
|
|
9
|
+
Cross-block reference recursion (traces_to, depends_on) is delegated to
|
|
10
|
+
shared/render-helpers.md — see that file for the depth contract, ambient
|
|
11
|
+
globals, and empty-array convention shared across all per-item macros.
|
|
12
|
+
-#}
|
|
13
|
+
{% from "shared/render-helpers.md" import render_id_list_inline %}
|
|
14
|
+
|
|
15
|
+
{% macro render_requirement(req, depth=0) %}
|
|
16
|
+
{% if req %}- **{{ req.id }}** [{{ req.priority }}] ({{ req.type }}, {{ req.status }}): {{ enforceBudget(req.description, "requirements", "requirements.items.description") }}{% if req.acceptance_criteria %}
|
|
17
|
+
Criteria: {% for ac in req.acceptance_criteria %}{{ enforceBudget(ac, "requirements", "requirements.items.acceptance_criteria.items") }}{% if not loop.last %}; {% endif %}{% endfor %}{% endif %}
|
|
18
|
+
{% if req.source %} Source: {{ req.source }}
|
|
19
|
+
{% endif %}{{ render_id_list_inline("Traces to", req.traces_to, depth) }}{{ render_id_list_inline("Depends on", req.depends_on, depth) }}{% endif %}
|
|
20
|
+
{% endmacro %}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `research` block.
|
|
3
|
+
|
|
4
|
+
Block schema: .project/schemas/research.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
+
|
|
6
|
+
Cross-block reference recursion (informs, informed_by, related_research,
|
|
7
|
+
produces_findings, supersedes, superseded_by) is delegated to
|
|
8
|
+
shared/render-helpers.md — see that file for the depth contract, ambient
|
|
9
|
+
globals, and empty-array convention.
|
|
10
|
+
|
|
11
|
+
Embedded substructures:
|
|
12
|
+
`grounding` is an object with dependencies/revisions/external_refs
|
|
13
|
+
string arrays — rendered inline as labelled sub-lists, never recursed.
|
|
14
|
+
`citations[]` carries label/path/lines/url/retrieved_at — labelled
|
|
15
|
+
pointers to source material, not block IDs; rendered inline.
|
|
16
|
+
`stale_conditions[]` and `scope[]` are simple string arrays rendered as
|
|
17
|
+
bullet sub-lists.
|
|
18
|
+
|
|
19
|
+
x-prompt-budget integration:
|
|
20
|
+
The schema annotates `findings_summary`, `question`, `method` with
|
|
21
|
+
`x-prompt-budget`. enforceBudget is wired for these per Plan 5.
|
|
22
|
+
-#}
|
|
23
|
+
{% from "shared/render-helpers.md" import render_id_list_block, render_id_single_block, render_optional_scalar %}
|
|
24
|
+
|
|
25
|
+
{% macro render_research(r, depth=0) %}
|
|
26
|
+
ID: {{ r.id }}
|
|
27
|
+
Title: {{ r.title }}
|
|
28
|
+
Status: {{ r.status }}
|
|
29
|
+
Layer: {{ r.layer }}
|
|
30
|
+
Type: {{ r.type }}
|
|
31
|
+
Created by: {{ r.created_by }}
|
|
32
|
+
Created at: {{ r.created_at }}
|
|
33
|
+
{{ render_optional_scalar("Modified by", r.modified_by) }}{{ render_optional_scalar("Modified at", r.modified_at) }}{{ render_optional_scalar("Conducted by", r.conducted_by) }}{{ render_optional_scalar("Conducted at", r.conducted_at) }}{{ render_optional_scalar("Grounded at", r.grounded_at) }}
|
|
34
|
+
Question:
|
|
35
|
+
{{ enforceBudget(r.question, "research", "research.items.question") }}
|
|
36
|
+
|
|
37
|
+
Method:
|
|
38
|
+
{{ enforceBudget(r.method, "research", "research.items.method") }}
|
|
39
|
+
|
|
40
|
+
{% if r.scope is defined %}Scope:
|
|
41
|
+
{% if r.scope | length > 0 %}{% for s in r.scope %} - {{ s }}
|
|
42
|
+
{% endfor %}{% else %} (none)
|
|
43
|
+
{% endif %}{% endif %}Findings summary:
|
|
44
|
+
{{ enforceBudget(r.findings_summary, "research", "research.items.findings_summary") }}
|
|
45
|
+
|
|
46
|
+
{% if r.findings_document %}Findings document: {{ r.findings_document }}
|
|
47
|
+
{% endif %}{% if r.grounding is defined %}Grounding:
|
|
48
|
+
{% if r.grounding.dependencies is defined %} Dependencies: {% if r.grounding.dependencies | length > 0 %}{% for d in r.grounding.dependencies %}{{ d }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
49
|
+
{% endif %}{% if r.grounding.revisions is defined %} Revisions: {% if r.grounding.revisions | length > 0 %}{% for rv in r.grounding.revisions %}{{ rv }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
50
|
+
{% endif %}{% if r.grounding.external_refs is defined %} External refs: {% if r.grounding.external_refs | length > 0 %}{% for er in r.grounding.external_refs %}{{ er }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
51
|
+
{% endif %}{% endif %}{% if r.stale_conditions is defined %}Stale conditions:
|
|
52
|
+
{% if r.stale_conditions | length > 0 %}{% for sc in r.stale_conditions %} - {{ sc }}
|
|
53
|
+
{% endfor %}{% else %} (none)
|
|
54
|
+
{% endif %}{% endif %}{% if r.citations is defined %}Citations:
|
|
55
|
+
{% if r.citations | length > 0 %}{% for c in r.citations %} - {{ c.label }}{% if c.path %} — path: {{ c.path }}{% if c.lines %}:{{ c.lines }}{% endif %}{% endif %}{% if c.url %} — url: {{ c.url }}{% endif %}{% if c.retrieved_at %} — retrieved_at: {{ c.retrieved_at }}{% endif %}
|
|
56
|
+
{% endfor %}{% else %} (none)
|
|
57
|
+
{% endif %}{% endif %}{{ render_id_list_block("Informs", r.informs, depth) }}{{ render_id_list_block("Informed by", r.informed_by, depth) }}{{ render_id_list_block("Related research", r.related_research, depth) }}{{ render_id_list_block("Produces findings", r.produces_findings, depth) }}{{ render_id_list_block("Supersedes", r.supersedes, depth) }}{{ render_id_single_block("Superseded by", r.superseded_by, depth) }}{% endmacro %}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `spec-reviews` block.
|
|
3
|
+
|
|
4
|
+
Block schema: .project/schemas/spec-reviews.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
+
|
|
6
|
+
Findings:
|
|
7
|
+
Each review carries an embedded findings registry (definitions/finding
|
|
8
|
+
in the schema). Findings are rendered inline as a sub-list under the
|
|
9
|
+
review body — they are not block items in their own right and have no
|
|
10
|
+
per-item macro of their own. Each finding's `produces_decision` (when
|
|
11
|
+
present and depth > 0) recurses into the decisions block via
|
|
12
|
+
resolve/render_recursive — that pattern stays inline because it has a
|
|
13
|
+
deeper indent (4 spaces) than the helper convention assumes and is
|
|
14
|
+
embedded in a finding-iteration loop rather than a top-level field.
|
|
15
|
+
`related_findings` on a finding refer to sibling findings within the
|
|
16
|
+
same review by their string ids; they are emitted as bare IDs (no
|
|
17
|
+
recursion — finding IDs are scoped to the review and not in the global
|
|
18
|
+
ID index).
|
|
19
|
+
|
|
20
|
+
Optional review-level scalars (target_revision, reviewer, completed_at,
|
|
21
|
+
clean) and the method body delegate to shared/render-helpers.md
|
|
22
|
+
render_optional_scalar where the shape matches.
|
|
23
|
+
-#}
|
|
24
|
+
{% from "shared/render-helpers.md" import render_optional_scalar %}
|
|
25
|
+
|
|
26
|
+
{% macro render_spec_review(rev, depth=0) %}
|
|
27
|
+
ID: {{ rev.id }}
|
|
28
|
+
Target: {{ rev.target }}
|
|
29
|
+
Status: {{ rev.status }}
|
|
30
|
+
Created by: {{ rev.created_by }}
|
|
31
|
+
Created at: {{ rev.created_at }}
|
|
32
|
+
{{ render_optional_scalar("Target revision", rev.target_revision) }}{{ render_optional_scalar("Reviewer", rev.reviewer) }}{{ render_optional_scalar("Completed at", rev.completed_at) }}{% if rev.clean is defined %}Clean: {{ rev.clean }}
|
|
33
|
+
{% endif %}{% if rev.method %}Method:
|
|
34
|
+
{{ enforceBudget(rev.method, "spec-reviews", "reviews.items.method") }}
|
|
35
|
+
|
|
36
|
+
{% endif %}{% if rev.scope is defined %}Scope:
|
|
37
|
+
{% if rev.scope | length > 0 %}{% for s in rev.scope %} - {{ s }}
|
|
38
|
+
{% endfor %}{% else %} (none)
|
|
39
|
+
{% endif %}{% endif %}Findings:
|
|
40
|
+
{% if rev.findings and rev.findings | length > 0 %}{% for f in rev.findings %} - {{ f.id }} [{{ f.severity }}/{{ f.category }}/{{ f.state }}] reporter={{ f.reporter }} at={{ f.created_at }}
|
|
41
|
+
Description: {{ enforceBudget(f.description, "spec-reviews", "reviews.items.findings.items.description") }}
|
|
42
|
+
{% if f.evidence %} Evidence: {{ f.evidence }}
|
|
43
|
+
{% endif %}{% if f.location %} Location: {{ f.location }}
|
|
44
|
+
{% endif %}{% if f.resolution %} Resolution: {{ f.resolution }}
|
|
45
|
+
{% endif %}{% if f.resolved_by %} Resolved by: {{ f.resolved_by }}
|
|
46
|
+
{% endif %}{% if f.resolved_at %} Resolved at: {{ f.resolved_at }}
|
|
47
|
+
{% endif %}{% if f.produces_decision %} Produces decision: {% if depth > 0 %}{% set loc = resolve(f.produces_decision) %}{% if loc %}
|
|
48
|
+
{{ render_recursive(loc, depth - 1) }}{% else %}{{ f.produces_decision }}{% endif %}{% else %}{{ f.produces_decision }}{% endif %}
|
|
49
|
+
{% endif %}{% if f.related_findings is defined %} Related findings: {% if f.related_findings | length > 0 %}{% for rf in f.related_findings %}{{ rf }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
50
|
+
{% endif %}{% endfor %}{% else %} (none)
|
|
51
|
+
{% endif %}{% endmacro %}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{#-
|
|
2
|
+
Per-item macro for the `tasks` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
+
|
|
4
|
+
Block schema: .project/schemas/tasks.schema.json. Each item is one task
|
|
5
|
+
inside data.tasks[]. Required: id (^TASK-\d{3,}$), description, status.
|
|
6
|
+
Optional: phase (string|integer), files, acceptance_criteria, depends_on
|
|
7
|
+
(other task IDs), assigned_agent, verification (verification ID), notes.
|
|
8
|
+
|
|
9
|
+
When status === "completed", schema additionally requires verification
|
|
10
|
+
(the if/then conditional in the schema).
|
|
11
|
+
|
|
12
|
+
Cross-block reference recursion (depends_on, verification) is delegated to
|
|
13
|
+
shared/render-helpers.md — see that file for the depth contract, ambient
|
|
14
|
+
globals, and empty-array convention. verification is rendered as a single
|
|
15
|
+
inline reference (one ID) rather than a list.
|
|
16
|
+
|
|
17
|
+
Files field:
|
|
18
|
+
files[] is a list of code paths, not project-block IDs. Rendered inline
|
|
19
|
+
as a comma-separated list; never recursed.
|
|
20
|
+
-#}
|
|
21
|
+
{% from "shared/render-helpers.md" import render_id_list_inline, render_id_single_inline %}
|
|
22
|
+
|
|
23
|
+
{% macro render_task(t, depth=0) %}
|
|
24
|
+
{% if t %}- **{{ t.id }}** [{{ t.status }}]: {{ enforceBudget(t.description, "tasks", "tasks.items.description") }}{% if t.phase %} (phase {{ t.phase }}){% endif %}{% if t.files %} — files: {{ t.files | join(", ") }}{% endif %}
|
|
25
|
+
{% if t.acceptance_criteria %} Criteria: {% for ac in t.acceptance_criteria %}{{ enforceBudget(ac, "tasks", "tasks.items.acceptance_criteria.items") }}{% if not loop.last %}; {% endif %}{% endfor %}
|
|
26
|
+
{% endif %}{% if t.assigned_agent %} Assigned agent: {{ t.assigned_agent }}
|
|
27
|
+
{% endif %}{% if t.notes %} Notes: {{ enforceBudget(t.notes, "tasks", "tasks.items.notes") }}
|
|
28
|
+
{% endif %}{{ render_id_list_inline("Depends on", t.depends_on, depth) }}{{ render_id_single_inline("Verification", t.verification, depth) }}{% endif %}
|
|
29
|
+
{% endmacro %}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
## Intent
|
|
2
|
+
|
|
3
|
+
{{ intent }}
|
|
4
|
+
|
|
5
|
+
## Existing Phases
|
|
6
|
+
|
|
7
|
+
{% for phase in phases %}
|
|
8
|
+
- Phase {{ phase.number }}: {{ phase.name }} ({{ phase.status }})
|
|
9
|
+
{% endfor %}
|
|
10
|
+
|
|
11
|
+
{% if architecture and architecture.modules %}
|
|
12
|
+
## Current Architecture
|
|
13
|
+
|
|
14
|
+
{% for module in architecture.modules %}
|
|
15
|
+
- **{{ module.name }}** ({{ module.file }}, {{ module.lines }} lines): {{ module.responsibility }}
|
|
16
|
+
{% endfor %}
|
|
17
|
+
|
|
18
|
+
{% if architecture.compilation_pipeline %}
|
|
19
|
+
### Compilation Pipeline
|
|
20
|
+
{% for stage in architecture.compilation_pipeline %}
|
|
21
|
+
{{ loop.index }}. **{{ stage.stage }}**: {{ stage.description }}
|
|
22
|
+
{% endfor %}
|
|
23
|
+
{% endif %}
|
|
24
|
+
{% endif %}
|
|
25
|
+
|
|
26
|
+
{% if conventions and conventions.rules %}
|
|
27
|
+
## Conventions
|
|
28
|
+
|
|
29
|
+
{% for rule in conventions.rules %}
|
|
30
|
+
- {{ rule.id }}: {{ rule.description }} ({{ rule.enforcement }})
|
|
31
|
+
{% endfor %}
|
|
32
|
+
{% endif %}
|
|
33
|
+
|
|
34
|
+
{% if gaps and gaps.gaps %}
|
|
35
|
+
## Current Gaps
|
|
36
|
+
|
|
37
|
+
{% for gap in gaps.gaps %}
|
|
38
|
+
{% if gap.status == "open" %}
|
|
39
|
+
- [{{ gap.priority }}] {{ gap.id }}: {{ gap.description }}
|
|
40
|
+
{% endif %}
|
|
41
|
+
{% endfor %}
|
|
42
|
+
{% endif %}
|
|
43
|
+
|
|
44
|
+
{% if inventory %}
|
|
45
|
+
## Current Inventory
|
|
46
|
+
|
|
47
|
+
{% if inventory.step_types %}- Step types: {{ inventory.step_types | length }}
|
|
48
|
+
{% endif %}{% if inventory.agent_specs %}- Agent specs: {{ inventory.agent_specs | length }}
|
|
49
|
+
{% endif %}{% if inventory.schemas %}- Schemas: {{ inventory.schemas | length }}
|
|
50
|
+
{% endif %}{% if inventory.test_count is defined %}- Tests: {{ inventory.test_count }}
|
|
51
|
+
{% endif %}{% endif %}
|
|
52
|
+
|
|
53
|
+
## Instructions
|
|
54
|
+
|
|
55
|
+
Convert the intent above into a structured phase spec. Read the codebase to understand what exists and what the intent requires.
|
|
56
|
+
|
|
57
|
+
1. **Determine the phase number** — next after the highest existing phase number
|
|
58
|
+
2. **Write a clear intent statement** — what this phase accomplishes and why
|
|
59
|
+
3. **Define success criteria** — each with a verify_method:
|
|
60
|
+
- `command`: can be verified by running a shell command (test suite, grep, validate)
|
|
61
|
+
- `inspect`: requires reading files and assessing content
|
|
62
|
+
- `human`: requires human judgment
|
|
63
|
+
4. **Decompose into specs** — each spec is a focused unit of work:
|
|
64
|
+
- Sequential numbering continuing from the last spec in the previous phase
|
|
65
|
+
- Clear intent per spec
|
|
66
|
+
- Concrete acceptance criteria (strings, each independently checkable)
|
|
67
|
+
- Specs should be ordered by dependency — earlier specs don't depend on later ones
|
|
68
|
+
5. **Identify dependencies** — which phase numbers this phase depends on
|
|
69
|
+
6. **List artifacts produced** — file paths this phase will create or modify
|
|
70
|
+
|
|
71
|
+
### Sizing guidance
|
|
72
|
+
|
|
73
|
+
- Each spec should be completable by one agent in one context window
|
|
74
|
+
- If a spec needs more than ~5 files changed, split it
|
|
75
|
+
- If a spec has more than ~5 acceptance criteria, it might be doing too much
|
|
76
|
+
- Group related changes (e.g., schema + instance + validation test = one spec)
|
|
77
|
+
|
|
78
|
+
### Cross-reference gaps
|
|
79
|
+
|
|
80
|
+
Check if any existing open gaps are addressed by this phase. If so, note that in the spec intent — the gap can be marked resolved when the spec completes.
|
|
81
|
+
|
|
82
|
+
Produce a JSON object conforming to the phase schema.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
## Project Identity
|
|
2
|
+
|
|
3
|
+
**Name:** {{ project.name }}
|
|
4
|
+
**Description:** {{ project.description }}
|
|
5
|
+
**Core Value:** {{ project.core_value }}
|
|
6
|
+
**Status:** {{ project.status }}
|
|
7
|
+
{% if project.stack %}
|
|
8
|
+
|
|
9
|
+
### Stack
|
|
10
|
+
{% for item in project.stack %}
|
|
11
|
+
- {{ item }}
|
|
12
|
+
{% endfor %}
|
|
13
|
+
{% endif %}
|
|
14
|
+
|
|
15
|
+
## Requirements Summary
|
|
16
|
+
|
|
17
|
+
{% for req in requirements.requirements %}
|
|
18
|
+
{% if req.priority == "must" %}
|
|
19
|
+
- **{{ req.id }}** [must/{{ req.type }}]: {{ req.description }}
|
|
20
|
+
{% endif %}
|
|
21
|
+
{% endfor %}
|
|
22
|
+
{% for req in requirements.requirements %}
|
|
23
|
+
{% if req.priority == "should" %}
|
|
24
|
+
- **{{ req.id }}** [should/{{ req.type }}]: {{ req.description }}
|
|
25
|
+
{% endif %}
|
|
26
|
+
{% endfor %}
|
|
27
|
+
{% for req in requirements.requirements %}
|
|
28
|
+
{% if req.priority == "could" %}
|
|
29
|
+
- **{{ req.id }}** [could/{{ req.type }}]: {{ req.description }}
|
|
30
|
+
{% endif %}
|
|
31
|
+
{% endfor %}
|
|
32
|
+
|
|
33
|
+
## Architecture
|
|
34
|
+
|
|
35
|
+
**Overview:** {{ architecture.overview }}
|
|
36
|
+
|
|
37
|
+
### Modules
|
|
38
|
+
{% for module in architecture.modules %}
|
|
39
|
+
- **{{ module.name }}** (`{{ module.file }}`): {{ module.responsibility }}{% if module.dependencies %} [depends: {{ module.dependencies | join(", ") }}]{% endif %}
|
|
40
|
+
{% endfor %}
|
|
41
|
+
|
|
42
|
+
### Patterns
|
|
43
|
+
{% for pattern in architecture.patterns %}
|
|
44
|
+
- **{{ pattern.name }}**: {{ pattern.description }} (used in: {{ pattern.used_in | join(", ") }})
|
|
45
|
+
{% endfor %}
|
|
46
|
+
|
|
47
|
+
### Boundaries
|
|
48
|
+
{% for boundary in architecture.boundaries %}
|
|
49
|
+
- {{ boundary }}
|
|
50
|
+
{% endfor %}
|
|
51
|
+
|
|
52
|
+
{% if existing_files %}
|
|
53
|
+
## Existing Project Files
|
|
54
|
+
|
|
55
|
+
The project directory already contains these files:
|
|
56
|
+
{% for file in existing_files %}
|
|
57
|
+
- {{ file }}
|
|
58
|
+
{% endfor %}
|
|
59
|
+
|
|
60
|
+
Account for existing structure — do not plan to recreate files that already exist unless they need modification.
|
|
61
|
+
{% endif %}
|
|
62
|
+
|
|
63
|
+
## Instructions
|
|
64
|
+
|
|
65
|
+
Create implementation phases and tasks that build this project incrementally. The plan should take the project from its current state ({{ project.status }}) to a working system that satisfies all "must" requirements and addresses "should" requirements.
|
|
66
|
+
|
|
67
|
+
### Phase guidelines
|
|
68
|
+
|
|
69
|
+
1. **Phase 1** — Foundation: project structure, core module scaffolding, configuration, initial tests
|
|
70
|
+
2. **Phase 2+** — Layer functionality in priority order: "must" requirements first, then "should"
|
|
71
|
+
3. **Final phase** — Integration, documentation, and verification
|
|
72
|
+
4. Each phase should represent a meaningful milestone — the project is more capable after each phase
|
|
73
|
+
5. A phase with more than 8-10 tasks is likely too large — split it
|
|
74
|
+
|
|
75
|
+
### For each phase, provide:
|
|
76
|
+
|
|
77
|
+
- **number** — sequential starting at 1
|
|
78
|
+
- **name** — short descriptive name
|
|
79
|
+
- **intent** — what this phase accomplishes and why it comes at this point
|
|
80
|
+
- **goal** — what is true after this phase that was not true before
|
|
81
|
+
- **status** — `"planned"`
|
|
82
|
+
- **success_criteria** — array of `{ criterion, verify_method }` (verify_method: "command", "inspect", or "test")
|
|
83
|
+
- **dependencies** — array of phase numbers this depends on (empty for phase 1)
|
|
84
|
+
- **inputs** — what this phase needs from prior phases or external sources
|
|
85
|
+
- **outputs** — what this phase produces for later phases or users
|
|
86
|
+
|
|
87
|
+
### For each task, provide:
|
|
88
|
+
|
|
89
|
+
- **id** — unique, formatted as T-001, T-002, etc.
|
|
90
|
+
- **description** — clear statement of what to do
|
|
91
|
+
- **status** — `"planned"`
|
|
92
|
+
- **phase** — phase number this belongs to
|
|
93
|
+
- **files** — array of file paths this task creates or modifies
|
|
94
|
+
- **acceptance_criteria** — array of specific, verifiable statements
|
|
95
|
+
- **depends_on** — array of task IDs this depends on (empty if none)
|
|
96
|
+
- **notes** — optional: any implementation guidance or caveats
|
|
97
|
+
|
|
98
|
+
### Task sizing
|
|
99
|
+
|
|
100
|
+
- Each task should be completable by one agent in one context window
|
|
101
|
+
- A task touching more than 3-5 files likely needs splitting
|
|
102
|
+
- A task with more than 5 acceptance criteria may be doing too much
|
|
103
|
+
- Group related changes: schema + implementation + test = one task when files are few
|
|
104
|
+
|
|
105
|
+
### Traceability
|
|
106
|
+
|
|
107
|
+
- Every "must" requirement should be addressed by at least one task
|
|
108
|
+
- Every task's files should map to at least one architecture module
|
|
109
|
+
- Note requirement IDs in task descriptions or notes where the mapping is clear
|
|
110
|
+
|
|
111
|
+
### Output format
|
|
112
|
+
|
|
113
|
+
Produce a single JSON object with two arrays:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"phases": [
|
|
118
|
+
{
|
|
119
|
+
"number": 1,
|
|
120
|
+
"name": "string",
|
|
121
|
+
"intent": "string",
|
|
122
|
+
"goal": "string",
|
|
123
|
+
"status": "planned",
|
|
124
|
+
"success_criteria": [{ "criterion": "string", "verify_method": "command" }],
|
|
125
|
+
"dependencies": [],
|
|
126
|
+
"inputs": ["string"],
|
|
127
|
+
"outputs": ["string"]
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"tasks": [
|
|
131
|
+
{
|
|
132
|
+
"id": "T-001",
|
|
133
|
+
"description": "string",
|
|
134
|
+
"status": "planned",
|
|
135
|
+
"phase": 1,
|
|
136
|
+
"files": ["src/file.ts"],
|
|
137
|
+
"acceptance_criteria": ["string"],
|
|
138
|
+
"depends_on": [],
|
|
139
|
+
"notes": "optional string"
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
## Phase: {{ phase.name }}
|
|
2
|
+
|
|
3
|
+
### Intent
|
|
4
|
+
{{ phase.intent }}
|
|
5
|
+
|
|
6
|
+
### Success Criteria
|
|
7
|
+
{% for criterion in phase.success_criteria %}
|
|
8
|
+
- {{ criterion.criterion }} (verify: {{ criterion.verify_method }})
|
|
9
|
+
{% endfor %}
|
|
10
|
+
|
|
11
|
+
### Specs
|
|
12
|
+
{% if phase.specs %}
|
|
13
|
+
{% for spec in phase.specs %}
|
|
14
|
+
- **{{ spec.id }}**: {{ spec.name }}
|
|
15
|
+
{% endfor %}
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
### Current Architecture
|
|
19
|
+
{% for module in architecture.modules %}
|
|
20
|
+
- **{{ module.name }}** ({{ module.file }}): {{ module.responsibility }}
|
|
21
|
+
{% endfor %}
|
|
22
|
+
|
|
23
|
+
### Conventions
|
|
24
|
+
{% for rule in conventions.rules %}
|
|
25
|
+
- {{ rule.id }}: {{ rule.description }} ({{ rule.enforcement }})
|
|
26
|
+
{% endfor %}
|
|
27
|
+
|
|
28
|
+
## Instructions
|
|
29
|
+
|
|
30
|
+
Decompose this phase into implementation plans. Each plan should be a focused unit of work that one agent can complete in a single context window.
|
|
31
|
+
|
|
32
|
+
Before creating plans:
|
|
33
|
+
1. Read source files referenced in the architecture to understand existing patterns
|
|
34
|
+
2. Identify logical boundaries — which specs or features are independent
|
|
35
|
+
3. Determine which plans can run in parallel (independent file sets)
|
|
36
|
+
|
|
37
|
+
For each plan, produce:
|
|
38
|
+
- **name**: short identifier for the plan
|
|
39
|
+
- **intent**: what this plan accomplishes and why
|
|
40
|
+
- **tasks**: concrete list of things to do (create files, add tests, wire up)
|
|
41
|
+
- **files_to_change**: paths that will be created or modified
|
|
42
|
+
- **acceptance_criteria**: how to know the plan is done
|
|
43
|
+
- **context_needed**: files or modules the implementing agent should read first
|
|
44
|
+
- **parallel_group**: group name — plans in the same group can run concurrently (independent file sets get the same group; dependent plans get different groups)
|
|
45
|
+
|
|
46
|
+
Output a JSON object with a `plans` array conforming to the plan-breakdown schema.
|