plan
Retrieves normalized agent plan histories, grouping by task and distinguishing final/draft revisions with user feedback.
Instructions
Normalized plan atoms for a session — final vs drafts, grouped by task.
Wraps query(type="plan_event", …) and normalizes every agent's plan
signal (Claude ExitPlanMode / Write plans/*.md, Codex
update_plan, Antigravity implementation_plan.md) into a single
:class:~ai_r.events.Plan shape — the per-agent signal is an internal
detail, never surfaced.
Plans are grouped by task keyed on each plan's task_key — the
plan-file slug when the agent has one (Claude plans/<slug>.md,
Antigravity implementation_plan.md path), falling back to the
normalized title only when no plan file exists (Codex update_plan).
Within a task the latest plan is final and earlier revisions are
draft; plans of earlier completed tasks are completed_major.
F3.4 default schema (measured ≈×3.7 cheaper than "everything inlined"):
the final plan's full text is inlined (body +
body_source — "approval_edited_by_user" when the user's
approval carried an edited plan, which is the AUTHORITATIVE text and
overrides the signal/file body, else "plan_signal"); drafts stay
references (bodies via get_body); every «plan quote → user comment»
pair extracted from the user's plan responses is returned under
feedback, each with a ref ("<session>:pf<N>") that
get_body resolves to the FULL raw response. Only agents with an
interactive plan-approval flow have the feedback signal (today: Claude —
an ExitPlanMode verdict or a rejected plan-file Write); others
honestly contribute nothing. Technical failures and bare no-comment
rejections are filtered out.
F3.4 v2 additions: every plan atom carries version — its 1-based
revision number within the task group, chronological (drafts are
v1…vN-1, the final is vN); every feedback pair carries
plan_version (the answered revision's number), round (1-based
feedback-round number within the session — one round per user response
that produced pairs) and section — the heading of the plan section
the quote anchors to. Quotes are selected from the RENDERED plan, so
the anchor match strips markdown markup from both sides; a quote that
matches no section — or more than one — gets an honest null
anchor, never a nearest guess.
Args:
session: Restrict to one session uuid (recommended).
kind: Optional filter — draft | final | completed_major.
group: Grouping strategy; only "task" is supported.
agent: Optional agent filter (claude/codex/opencode/antigravity/pi).
redact: When True (default) secrets in the emitted plan/feedback
fields (title/steps/body/quote/comment…)
are masked as [REDACTED_<TYPE>] and the response carries a
redactions type→count dict when any replacement happened;
False returns raw content.
bodies: "final" (default) inlines the final plan's full text;
"none" returns reference-only atoms.
feedback: True (default) adds the feedback pair list +
feedback_count; False omits both (historical shape).
rounds: "all" (default) returns every feedback round;
"last" keeps only each session's final round (v2). Any
other value fails loud.
Returns:
{"plans": [...], "count": N, "feedback": [...], "feedback_count": M} — each plan carries
id/session_id/agent/title/task_id/kind/version/path/steps/status/ refs/sha256 (+ body/body_source on the final when
bodies="final"); each feedback pair carries
session_id/agent/plan_id/plan_version/verdict/round/quote/comment/ section/ref/ts (verdict ∈ rejected | stay_in_plan_mode;
quote is null for a free-text comment; plan_version/
section are null without a signal). Draft bodies and raw
responses stay on-demand via :func:get_body. Standard
{"error": ..., "message": ...} dict on invalid arguments.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | ||
| agent | No | ||
| group | No | task | |
| bodies | No | final | |
| redact | No | ||
| rounds | No | all | |
| session | No | ||
| feedback | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||