Skip to content

feat: bidirectional AI conversation, context persistence, and approve-with-notes#317

Open
sudorest wants to merge 1 commit intobacknotprop:mainfrom
sudorest:feat/bidirectional-conversation-and-context-persistence
Open

feat: bidirectional AI conversation, context persistence, and approve-with-notes#317
sudorest wants to merge 1 commit intobacknotprop:mainfrom
sudorest:feat/bidirectional-conversation-and-context-persistence

Conversation

@sudorest
Copy link

Summary

This PR addresses two major user complaints and adds three interconnected features inspired by Octto's branch-based Q&A patterns:

  1. Approve with Notes — Users can now add annotations AND approve the plan in one step. No more forced choice between "approve silently" or "deny with feedback."

  2. Context Persistence — Review sessions now survive across deny/revise cycles. Previous iterations' feedback, questions, and answers are accumulated and fed back to the AI with each revision.

  3. Bidirectional AI Conversation — The AI can now embed clarification questions in plans that appear as interactive question cards in the review UI. Users answer visually; responses flow back through the approve/deny feedback loop.

Changes

Phase 1: Approve with Notes (smallest change, immediate value)

  • packages/shared/feedback-templates.ts: New planApproveWithNotesFeedback() template
  • apps/hook/server/index.ts: Pass user annotations through as message field in the allow decision (Claude Code)
  • packages/editor/App.tsx: Replace "Annotations Won't Be Sent" warning with "Approve with Notes" confirmation dialog; always show full-green Approve button

Phase 2: Context Persistence

  • packages/shared/questions.ts (NEW): Types for ReviewIteration, ReviewSession, ClarificationQuestion, QuestionAnswer; plan metadata parsing (extractSessionId, extractQuestions, stripPlanMetadata)
  • packages/server/review-session.ts (NEW): Session persistence to ~/.plannotator/sessions/, with auto-cleanup of sessions older than 7 days
  • packages/shared/feedback-templates.ts: Enhanced planDenyFeedback() now includes accumulated iteration history and Q&A context
  • apps/hook/server/index.ts & apps/opencode-plugin/index.ts: Session tracking (extract/generate ID, load previous iterations, record after decision)
  • packages/server/index.ts: New GET /api/session endpoint for UI to fetch session state
  • packages/ui/components/sidebar/ReviewHistory.tsx (NEW): Review History sidebar tab with iteration timeline, expandable feedback summaries, and Q&A display
  • packages/ui/components/sidebar/SidebarContainer.tsx & SidebarTabs.tsx: History tab integration
  • packages/ui/hooks/useSidebar.ts: Added "history" to SidebarTab type

Phase 3: Bidirectional AI Conversation

  • packages/server/questions.ts (NEW): Question session management with waiters, answer submission, and state tracking
  • packages/server/index.ts: WebSocket support via Bun's native WS, POST /api/answers and GET /api/questions endpoints, answers included in decision resolution
  • packages/shared/prompts.ts (NEW): CLARIFICATION_QUESTIONS_PROMPT teaching AI the question embedding format
  • packages/ui/components/ClarificationPanel.tsx (NEW): Modal panel with 5 question types (pick_one, pick_many, confirm, ask_text, show_options), badge with pulse animation, answered/unanswered states
  • packages/editor/App.tsx: WebSocket connection for real-time question updates, answer submission handler, ClarificationBadge in header, panel overlay

How It Works

AI Embeds Questions in Plans

<!-- plannotator:session ps_1710567890_abc123 -->

# My Plan

Here's the plan content...

<!-- plannotator:questions [
  {"id":"q1","type":"pick_one","question":"Which database?",
   "options":[{"id":"pg","label":"PostgreSQL","recommended":true},
              {"id":"sqlite","label":"SQLite"}]}
] -->

Session Continuity

When a plan is denied, the feedback includes:

  • Current annotations
  • Previous iteration summaries
  • Answered clarification questions
  • A hint for the AI to include <!-- plannotator:session ID --> in the next submission

Question Types

Type UI Widget
pick_one Radio buttons with descriptions
pick_many Checkboxes with multi-select
confirm Yes/No buttons
ask_text Textarea input
show_options Cards with pros/cons lists

Files Changed

File Status
packages/shared/questions.ts NEW
packages/shared/prompts.ts NEW
packages/shared/feedback-templates.ts Modified
packages/server/index.ts Modified
packages/server/questions.ts NEW
packages/server/review-session.ts NEW
packages/editor/App.tsx Modified
packages/ui/components/ClarificationPanel.tsx NEW
packages/ui/components/sidebar/ReviewHistory.tsx NEW
packages/ui/components/sidebar/SidebarContainer.tsx Modified
packages/ui/components/sidebar/SidebarTabs.tsx Modified
packages/ui/hooks/useSidebar.ts Modified
apps/hook/server/index.ts Modified
apps/opencode-plugin/index.ts Modified

14 files changed, ~2000 lines added

…rove-with-notes

Phase 1 - Approve with Comments:
- Replace 'Annotations Won't Be Sent' warning with 'Approve with Notes' flow
- Pass user annotations through as implementation notes on approve (Claude Code)
- Add planApproveWithNotesFeedback() shared template

Phase 2 - Context Persistence:
- Track review sessions across deny/revise cycles with session IDs
- Persist iterations to ~/.plannotator/sessions/ with Q&A history
- Enhanced planDenyFeedback() includes previous iteration context
- Add Review History sidebar tab showing iteration timeline
- Plan metadata embedding (session ID, questions) via HTML comments

Phase 3 - Bidirectional AI Conversation:
- AI can embed clarification questions in plans via structured metadata
- WebSocket support in plan server for real-time question updates
- ClarificationPanel UI with 5 question types (pick_one, pick_many,
  confirm, ask_text, show_options)
- Question answers flow back to AI through approve/deny feedback
- CLARIFICATION_QUESTIONS_PROMPT teaches AI the question format

Inspired by github.com/vtemian/octto branch-based Q&A patterns.
@backnotprop
Copy link
Owner

Big feature, thanks. Was thinking about this myself.

Ill review shortly.

@backnotprop
Copy link
Owner

Question

Phase 1: Approve with Notes (smallest change, immediate value)
packages/shared/feedback-templates.ts: New planApproveWithNotesFeedback() template
apps/hook/server/index.ts: Pass user annotations through as message field in the allow decision (Claude Code)
packages/editor/App.tsx: Replace "Annotations Won't Be Sent" warning with "Approve with Notes" confirmation dialog; always show full-green Approve button

I dont think this is actually supported by the claude hook though, or did they update it?

@sudorest
Copy link
Author

⚠️ Known Issue: "Approve with Notes" on Claude Code Hook

After further investigation of the Claude Code hooks documentation, the Phase 1 "Approve with Notes" feature does not work as implemented for the Claude Code hook.

The Problem

The PermissionRequest decision control only supports the message field on "deny" — not on "allow":

Field Description
behavior "allow" grants the permission, "deny" denies it
updatedInput For "allow" only
updatedPermissions For "allow" only
message For "deny" only: tells Claude why the permission was denied
interrupt For "deny" only

So the current code in apps/hook/server/index.ts that does:

decision: {
  behavior: "allow",
  message: planApproveWithNotesFeedback(result.feedback)  // ← silently ignored by Claude Code
}

...will have the message silently discarded. The plan proceeds but the user's annotations/notes are lost.

The OpenCode plugin is fine

The OpenCode plugin (apps/opencode-plugin/index.ts) uses a tool-based approach (submit_plan tool) where the return string is the feedback — so approve-with-notes already works correctly there.

Possible fixes for Claude Code

  1. "Deny-as-approve" pattern: When user selects "Approve with Notes", actually send behavior: "deny" with a softer message like "Plan approved with minor notes — proceed with implementation, incorporating these suggestions...". The AI sees it as a deny but the tone guides it to continue rather than fully re-plan.

  2. PostToolUse hook: Send allow, then use a separate PostToolUse hook on ExitPlanMode to inject notes as context. More complex but semantically correct.

  3. Skip for Claude Code: Only support approve-with-notes for OpenCode. For Claude Code, revert to the original warning dialog behavior.

The rest of the PR (Phase 2: Context Persistence, Phase 3: Bidirectional Conversation) is unaffected by this issue since those features use the deny path for feedback delivery.

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.

2 participants