-
Notifications
You must be signed in to change notification settings - Fork 263
docs(rfd): Add new plan variants #902
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+166
−1
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| --- | ||
| title: "Plan Operations Support" | ||
| --- | ||
|
|
||
| Author(s): [anna239](https://github.com/anna239) | ||
|
|
||
| ## Elevator pitch | ||
|
|
||
| > What are you proposing to change? | ||
|
|
||
| Introduce a new `plan_update` session update type that supports multiple plan formats (item-based, file-based, markdown text), multiple concurrent plans via IDs, and plan removal. The existing `plan` session update type remains unchanged for backward compatibility. | ||
|
|
||
| ## Status quo | ||
|
|
||
| > How do things work today and what problems does this cause? Why would we change things? | ||
|
|
||
| - The `plan` session update contains `entries: Vec<PlanEntry>` — a flat list of items with priority/status | ||
| - Plans are one-way notifications (agent → client) via `session/update` | ||
| - No plan identity — each update replaces the previous plan entirely | ||
| - No way to remove/dismiss a plan once sent | ||
| - Only one plan representation (structured items) — no support for free-form markdown or file-based plans | ||
|
|
||
| ## What we propose to do about it | ||
|
|
||
| > What are you proposing to improve the situation? | ||
|
|
||
| Add a new `SessionUpdate` variant — `plan_update` — that carries a `plan` field. The `plan` field is a tagged union (discriminated by `type`) with the following variants: | ||
|
|
||
| | Type | Description | Specific fields | | ||
| | ---------- | ----------------------------------------------------- | ---------------------- | | ||
| | `items` | Structured entries (same semantics as today's `plan`) | `entries: PlanEntry[]` | | ||
| | `file` | Agent provides a file URI containing the plan | `uri: string` | | ||
| | `markdown` | Agent provides raw markdown text | `content: string` | | ||
|
|
||
| All variants carry a required `id: string` that identifies the plan, and an optional `_meta` for extensibility. | ||
|
|
||
| Additionally, introduce a `plan_removed` session update type that carries only a plan `id` to signal dismissal. This keeps `plan_update` focused purely on content updates and makes removal a distinct, self-describing event. | ||
|
|
||
| The existing `plan` session update type is **not modified** and continues to work as before. Agents that want multi-plan support, new plan formats, or removal capabilities use `plan_update` and `plan_removed` instead. | ||
|
|
||
| ### Client Capabilities | ||
|
|
||
| Add to `ClientCapabilities`: | ||
|
|
||
| ``` | ||
| planCapabilities: PlanCapabilities? = undefined | ||
| ``` | ||
|
|
||
| When present (`{}`), signals the client supports the `plan_update` and `plan_removed` session update types. When absent, the agent must fall back to the existing `plan` session update type. | ||
|
|
||
| ### Multiple Plans | ||
|
|
||
| The `id` field on every plan variant identifies a specific plan. | ||
|
|
||
| - Each `plan_update` targets the plan with the given `id` | ||
| - Client tracks plans by ID; updates replace the content of that specific plan | ||
| - Different plans may use different types (e.g., one `items` plan and one `markdown` plan) | ||
|
|
||
| ### Plan Removal | ||
|
|
||
| Agent sends a `plan_removed` session update with the plan's `id` to dismiss it. This is a separate session update type from `plan_update`, keeping content updates and lifecycle events distinct. | ||
|
benbrandt marked this conversation as resolved.
|
||
|
|
||
| ## Shiny future | ||
|
|
||
| > How will things will play out once this feature exists? | ||
|
|
||
| Agents will be able to present plans in the format most natural to them — structured checklists for step-by-step execution, markdown for free-form design docs, or file URIs for large plans generated externally. Clients that support `plan_update` can show multiple concurrent plans (e.g., a high-level strategy and a detailed implementation checklist), and dismiss plans that are no longer relevant. Clients that don't advertise `planCapabilities` continue to receive the existing `plan` updates with no changes. | ||
|
|
||
| ## Implementation details and plan | ||
|
|
||
| > Tell me more about your implementation. What is your detailed implementation plan? | ||
|
|
||
| ### Json Format Examples | ||
|
|
||
| Existing `plan` (unchanged): | ||
|
|
||
| ```json | ||
| { | ||
| "sessionUpdate": "plan", | ||
| "entries": [{ "content": "Step 1", "priority": "high", "status": "pending" }] | ||
| } | ||
| ``` | ||
|
|
||
| Item-based (`plan_update`): | ||
|
|
||
| ```json | ||
| { | ||
| "sessionUpdate": "plan_update", | ||
| "plan": { | ||
| "type": "items", | ||
| "id": "plan-1", | ||
| "entries": [ | ||
| { "content": "Step 1", "priority": "high", "status": "pending" } | ||
|
benbrandt marked this conversation as resolved.
|
||
| ] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Markdown: | ||
|
|
||
| ```json | ||
| { | ||
| "sessionUpdate": "plan_update", | ||
| "plan": { | ||
| "type": "markdown", | ||
| "id": "plan-1", | ||
| "content": "## Steps\n- [ ] Refactor module\n- [ ] Add tests" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| File-based: | ||
|
|
||
| ```json | ||
| { | ||
| "sessionUpdate": "plan_update", | ||
| "plan": { | ||
| "type": "file", | ||
| "id": "design-doc", | ||
| "uri": "file:///tmp/plan.md" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Removal: | ||
|
|
||
| ```json | ||
| { | ||
| "sessionUpdate": "plan_removed", | ||
| "id": "plan-1" | ||
| } | ||
| ``` | ||
|
|
||
| ## Frequently asked questions | ||
|
|
||
| > What questions have arisen over the course of authoring this document or during subsequent discussions? | ||
|
|
||
| ### Why a new session update type instead of extending the existing `plan`? | ||
|
|
||
| The existing `plan` variant flattens `Plan`'s `entries` field directly into the `SessionUpdate` discriminated union object. Adding a nested `plan` field, optional `id`, and polymorphic types to the same variant would require breaking the existing format or complex dual-deserialization logic. A new `plan_update` variant avoids this entirely — old clients ignore it, new clients handle both. | ||
|
|
||
| ### Why a separate `plan_removed` session update type instead of a removal variant inside `plan_update`? | ||
|
|
||
| Keeping removal as a separate session update type means `plan_update`'s `type` discriminator only covers content variants (`items`, `file`, `markdown`), making the schema cleaner. | ||
|
|
||
| ### Why plan-specific markdown and not a generic markdown content API? | ||
|
|
||
| A generic "agent shares markdown document" API would be simpler and more reusable. However, keeping it plan-typed enables clients to build plan-aware UX: selecting plan steps for partial execution, tracking plan progress, showing plan history. A generic markdown block wouldn't carry this semantic meaning. If future use cases need generic markdown sharing, that can be a separate feature. | ||
|
|
||
| ### What alternative approaches did you consider, and why did you settle on this one? | ||
|
|
||
| 1. **Extending the existing `plan` variant**: Would break backward compatibility or require complex dual-format deserialization. | ||
| 2. **`"type": "removed"` variant inside `plan_update`**: Instead of a separate `plan_removed` session update type, removal could be a variant in the `plan_update` tagged union (e.g., `"type": "removed"`). This keeps the entire plan lifecycle within a single update type. The tradeoff is that the `type` discriminator mixes content variants with a lifecycle event, making the schema less clean. | ||
|
|
||
| ## Revision history | ||
|
|
||
| 2026-04-02: Initial draft | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.