Skip to content

feat(plan): richer PlanArtifact schema for v0.9.0 (#2691)#2733

Open
idling11 wants to merge 2 commits into
Hmbown:mainfrom
idling11:feat/plan-artifact-schema
Open

feat(plan): richer PlanArtifact schema for v0.9.0 (#2691)#2733
idling11 wants to merge 2 commits into
Hmbown:mainfrom
idling11:feat/plan-artifact-schema

Conversation

@idling11
Copy link
Copy Markdown
Contributor

@idling11 idling11 commented Jun 4, 2026

Extend update_plan and PlanState with structured fields so Plan mode produces a grounded, reviewable artifact instead of just a step list. Backward-compatible: legacy callers sending only plan + explanation still work.

New fields (all optional, all default to None/empty):

  • title, objective, context_summary
  • sources_used, constraints (Vec)
  • recommended_approach
  • verification_plan, risks_and_unknowns
  • handoff_packet

Changes:

  • crates/tui/src/tools/plan.rs:
    • Extend UpdatePlanArgs with 9 new optional fields + Default derive
    • Extend PlanState to store all new fields
    • Extend PlanSnapshot with skip-serializing-when-empty annotations
    • Add accessor methods for all fields
    • Update tool schema, description, and execute to parse new fields
    • 6 new unit tests covering legacy compat, full artifact parse, snapshot serialization, is_empty, and Default
  • crates/tui/src/prompts/modes/plan.md:
    • Prompt now asks for grounded artifact fields
  • crates/tui/src/tui/app.rs, crates/tui/src/commands/mod.rs:
    • Update test struct literals with ..Default::default()

Closes #2691

Summary

Testing

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features
  • cargo test --workspace --all-features

Checklist

  • Updated docs or comments as needed
  • Added or updated tests where relevant
  • Verified TUI behavior manually if UI changes

Greptile Summary

This PR extends update_plan and PlanState with nine new optional fields (title, objective, context_summary, sources_used, constraints, recommended_approach, verification_plan, risks_and_unknowns, handoff_packet) to produce a richer, reviewable plan artifact instead of just a step list.

  • plan.rs: UpdatePlanArgs, PlanState, and PlanSnapshot are all extended with the new fields; is_empty(), update(), snapshot(), and the accessor methods are correctly updated; six new unit tests cover legacy compat, full artifact parsing, snapshot serialization, and Default.
  • plan.md: Prompt is updated to describe the new fields and correctly marks all but plan as optional.
  • commands/mod.rs and app.rs: Test struct literals are updated with ..Default::default() to compile against the expanded struct.

Confidence Score: 4/5

Safe to merge after fixing the required-fields mismatch in the JSON schema.

The input_schema() declares all nine new fields as required, but both the tool description and plan.md state they are optional, and the execute path treats them as optional. A model strictly following the schema will feel compelled to populate every field on every invocation rather than including only what was discovered, defeating the design intent and breaking the stated legacy compatibility path.

crates/tui/src/tools/plan.rs — the required array in input_schema() needs to be reduced to ["plan"].

Important Files Changed

Filename Overview
crates/tui/src/tools/plan.rs Core plan schema extension: adds 9 new optional fields to UpdatePlanArgs, PlanState, and PlanSnapshot. is_empty() and snapshot() are correctly updated, but input_schema() lists all new fields as required, contradicting the tool description and plan.md which both say these fields are optional.
crates/tui/src/prompts/modes/plan.md Prompt updated to describe all new plan artifact fields; correctly states all fields except plan are optional.
crates/tui/src/commands/mod.rs Test struct literal updated with ..Default::default() for backward compatibility; the /status output block still only reads explanation and items, silently dropping the new fields.
crates/tui/src/tui/app.rs Test struct literal updated with ..Default::default() — minimal mechanical change, no issues.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[LLM calls update_plan] --> B{Schema required check}
    B -->|Schema lists ALL 10 fields as required| C[LLM populates every field]
    B -->|Description and plan.md say only plan is required| D[LLM includes only discovered fields]
    C --> E[execute: opt_str / opt_strs parse input]
    D --> E
    E --> F[UpdatePlanArgs all new fields are Option or Vec]
    F --> G[PlanState.update]
    G --> H[Optional string fields stored as Option]
    G --> I[sources_used and constraints stored as Vec]
    H --> J[PlanState.snapshot]
    I --> J
    J --> K[PlanSnapshot with skip_serializing_if annotations]
    K --> L[Sidebar display]
    K --> M[status command only reads explanation and items]
Loading

Comments Outside Diff (1)

  1. crates/tui/src/commands/mod.rs, line 855-865 (link)

    P2 Status dump not updated for new plan fields

    This block still only reads snapshot.explanation and snapshot.items. The new fields (title, objective, sources_used, constraints, recommended_approach, verification_plan, risks_and_unknowns, handoff_packet) are silently dropped when this status output is produced. If the status command is used as context during an Agent-mode handoff or review, none of the richer artifact data will appear.

    Fix in Codex Fix in Claude Code Fix in Cursor

Fix All in Codex Fix All in Claude Code Fix All in Cursor

Reviews (3): Last reviewed commit: "fix(plan): check all new fields in PlanS..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Extend `update_plan` and `PlanState` with structured fields so Plan
mode produces a grounded, reviewable artifact instead of just a step
list. Backward-compatible: legacy callers sending only `plan` +
`explanation` still work.

New fields (all optional, all default to None/empty):
- `title`, `objective`, `context_summary`
- `sources_used`, `constraints` (Vec<String>)
- `recommended_approach`
- `verification_plan`, `risks_and_unknowns`
- `handoff_packet`

Changes:
- `crates/tui/src/tools/plan.rs`:
  - Extend `UpdatePlanArgs` with 9 new optional fields + Default derive
  - Extend `PlanState` to store all new fields
  - Extend `PlanSnapshot` with skip-serializing-when-empty annotations
  - Add accessor methods for all fields
  - Update tool schema, description, and execute to parse new fields
  - 6 new unit tests covering legacy compat, full artifact parse,
    snapshot serialization, is_empty, and Default
- `crates/tui/src/prompts/modes/plan.md`:
  - Prompt now asks for grounded artifact fields
- `crates/tui/src/tui/app.rs`, `crates/tui/src/commands/mod.rs`:
  - Update test struct literals with `..Default::default()`

Closes Hmbown#2691
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 4, 2026

Thanks @idling11 for taking the time to contribute.

This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this pull request is staying open. When enforcement is enabled, pull requests from contributors who are not listed in .github/APPROVED_CONTRIBUTORS will be closed automatically.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant PR access by commenting /lgtm on a pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several new fields (such as title, objective, context_summary, sources_used, constraints, recommended_approach, verification_plan, risks_and_unknowns, and handoff_packet) to the structured implementation plan artifact (UpdatePlanArgs, PlanSnapshot, and PlanState) in crates/tui/src/tools/plan.rs. It also updates the tool's description, schema, documentation, and adds corresponding tests. The reviewer pointed out that the is_empty method in PlanState misses checking several of these newly added fields, which could cause a non-empty plan to be incorrectly reported as empty, and provided a suggestion to fix this.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 185 to 196
pub fn is_empty(&self) -> bool {
self.steps.is_empty() && self.explanation.as_deref().unwrap_or("").is_empty()
self.steps.is_empty()
&& self.explanation.as_deref().unwrap_or("").is_empty()
&& self.title.as_deref().unwrap_or("").is_empty()
&& self.objective.as_deref().unwrap_or("").is_empty()
&& self.context_summary.as_deref().unwrap_or("").is_empty()
&& self
.recommended_approach
.as_deref()
.unwrap_or("")
.is_empty()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The is_empty method does not check several of the newly added fields, such as sources_used, constraints, verification_plan, risks_and_unknowns, and handoff_packet. If a plan contains only these fields, is_empty will incorrectly return true.

Suggested change
pub fn is_empty(&self) -> bool {
self.steps.is_empty() && self.explanation.as_deref().unwrap_or("").is_empty()
self.steps.is_empty()
&& self.explanation.as_deref().unwrap_or("").is_empty()
&& self.title.as_deref().unwrap_or("").is_empty()
&& self.objective.as_deref().unwrap_or("").is_empty()
&& self.context_summary.as_deref().unwrap_or("").is_empty()
&& self
.recommended_approach
.as_deref()
.unwrap_or("")
.is_empty()
}
pub fn is_empty(&self) -> bool {
self.steps.is_empty()
&& self.explanation.as_deref().unwrap_or("").is_empty()
&& self.title.as_deref().unwrap_or("").is_empty()
&& self.objective.as_deref().unwrap_or("").is_empty()
&& self.context_summary.as_deref().unwrap_or("").is_empty()
&& self.recommended_approach.as_deref().unwrap_or("").is_empty()
&& self.sources_used.is_empty()
&& self.constraints.is_empty()
&& self.verification_plan.as_deref().unwrap_or("").is_empty()
&& self.risks_and_unknowns.as_deref().unwrap_or("").is_empty()
&& self.handoff_packet.as_deref().unwrap_or("").is_empty()
}

Comment thread crates/tui/src/tools/plan.rs
@Hmbown
Copy link
Copy Markdown
Owner

Hmbown commented Jun 4, 2026

brilliant - thank you!!

@idling11 idling11 force-pushed the feat/plan-artifact-schema branch from 18b1f3e to 546265a Compare June 4, 2026 05:07
Comment on lines +516 to +527
"required": [
"title",
"objective",
"context_summary",
"sources_used",
"constraints",
"recommended_approach",
"plan",
"verification_plan",
"risks_and_unknowns",
"handoff_packet"
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 The required array in the JSON schema lists all 9 new fields as mandatory, directly contradicting the tool description ("All fields except plan are optional"), the plan.md prompt ("All fields except plan are optional"), and the PR's backward-compatibility claim. Because LLMs treat required as binding, the model will attempt to populate every field on every call — even when it has nothing meaningful to say — rather than only including what was actually discovered. A caller that sends only plan + explanation would also violate this schema, breaking the promised legacy path.

Suggested change
"required": [
"title",
"objective",
"context_summary",
"sources_used",
"constraints",
"recommended_approach",
"plan",
"verification_plan",
"risks_and_unknowns",
"handoff_packet"
]
"required": [
"plan"
]

Fix in Codex Fix in Claude Code Fix in Cursor

@idling11
Copy link
Copy Markdown
Contributor Author

idling11 commented Jun 4, 2026

brilliant - thank you!!

#2689 and #2690, I've already implemented these two issues in two separate pull requests locally, but they need to be gave after this pull request proceed. Thanks for the review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v0.9.0 Plan artifact schema: require sources, constraints, risks, and verification

2 participants