Skip to content

feat: add first-class host UX for plan management #3844

Description

@aheritier

Problem / context

docker-agent now has plan primitives, but plan management is still primarily an agent/tool concern. A human using the host TUI or CLI cannot reliably discover, inspect, switch, approve, resume, or export plans as a first-class workflow. This makes plans hard to use across turns and frontends, and leaves host applications to reconstruct state from tool events or files.

This is a host-UX enhancement, not a replacement for the existing plan toolsets or their storage work. The goal is to expose the same plan lifecycle through stable host surfaces while preserving the existing agent-facing collaboration model.

Relevant history and prior art:

  • #2788 proposed /plan, approval UX, and plan/execution separation; it was closed after implementation direction moved to readonly planner sub-agents and dedicated plan tools.
  • #3227 / #3237 introduced the shared plan toolset and its pluggable storage direction.
  • #3239 added the storage interface.
  • #3263 covered file-based revisions, export, free-form status, and optimistic locking.
  • #3274 implemented revisions/status/locking work.
  • #3292 and #3305 established the per-session markdown plan and exit_plan_mode marker alongside the shared plan toolset.
  • #3140 and #3168 are related plan-mode/persona history.

Those changes are complementary. This issue addresses the missing host-facing management layer and must not duplicate or regress the shared, cross-session plan capability.

Goals

  • Make plans discoverable and manageable from the TUI without requiring knowledge of tool names or storage paths.
  • Provide a scriptable CLI surface with stable, machine-readable output.
  • Reuse the existing plan/session-plan abstractions and storage/concurrency semantics rather than creating a second plan database.
  • Make status, revision, and conflict information visible to users.
  • Keep host UX usable for both shared named plans and the current session plan where supported.
  • Define one host contract that future API/frontends can consume.

Non-goals

  • Replacing plan or session_plan toolsets, their storage backends, or agent prompts.
  • Automatically approving plans or turning every tool call into an approval prompt.
  • Designing a new project/task tracker, dependency graph, or GitHub integration.
  • Changing plan content semantics, free-form status semantics, or optimistic-locking rules already established by the plan implementation.
  • Requiring a TUI to use the CLI internally, or making headless execution interactive.

User stories

  • As a TUI user, I can list plans, see status/revision/updated time, and open one without leaving the session.
  • As a TUI user, I can create, rename/select, edit, export, archive/delete, and resume a plan with clear confirmation for destructive actions.
  • As an agent operator, I can see when a plan is awaiting review, in progress, blocked, done, or conflicted.
  • As a CLI/script user, I can list and inspect plans as JSON, update status/content with an expected revision, and receive a non-zero conflict result when stale.
  • As a headless caller, I can use the same operations without TUI-only assumptions or ANSI output.
  • As a team using shared plans, I can safely observe and update plans across sessions without silent last-write-wins overwrites.

Proposed UX

TUI

Add a discoverable plan browser (for example /plans) and a plan detail/editor flow. Exact key bindings are a decision below, but the interaction should support list, filter/open, create, edit, status update, export, and delete/archive. The active plan and status should be visible without obscuring the conversation.

Illustrative rendering:

╭─ Plans ──────────────────────────────────────────────────────────────╮
│ > release-prep       in-progress   v7   updated 2m ago              │
│   api-migration      blocked       v3   updated yesterday            │
│   session plan       awaiting-review                                  │
│                                                                     │
│ [Enter] Open  [n] New  [e] Edit  [s] Status  [x] Export  [d] Delete │
╰─────────────────────────────────────────────────────────────────────╯
╭─ Plan: release-prep · in-progress · v7 ─────────────────────────────╮
│  1. Validate the release configuration                               │
│  2. Run the compatibility test matrix                               │
│  3. Publish the signed artifacts                                     │
│                                                                     │
│ Last updated by session abc123.  Optimistic-lock revision: 7         │
│ [Edit] [Set status] [Export] [Refresh] [Back]                       │
╰─────────────────────────────────────────────────────────────────────╯

For a stale update, show an actionable conflict (refresh/review/ retry) and never silently overwrite the newer revision. Destructive operations require confirmation and should identify the plan name.

CLI

Introduce a command group under the existing CLI convention (exact command name is a decision):

docker agent plans list [--json]
docker agent plans get <name> [--json]
docker agent plans create <name> [--file <path>]
docker agent plans update <name> [--file <path>] [--expected-version <n>]
docker agent plans status <name> <status> [--expected-version <n>]
docker agent plans export <name> --output <path>
docker agent plans delete <name> [--force]

Human output is concise and readable; --json has stable fields (name/id, content or content reference, status, version, timestamps, and storage/session identity as applicable). Errors, including optimistic-lock conflicts, are machine-detectable and include the current version when safe.

Architecture and constraints

  • Define a host-facing service/interface around the existing shared-plan and session-plan implementations; TUI and CLI must call that interface rather than duplicate filesystem or storage logic.
  • Preserve pluggable storage. Do not assume local files in the host layer; storage errors must remain distinguishable from not-found and conflict errors.
  • Preserve atomic writes, validation, revisions, and optimistic locking. Every mutating operation that can race accepts an expected version or has an explicit safe replacement policy.
  • Keep shared named plans and ephemeral per-session plans distinct in the model and UX; never expose a session plan as if it were globally shareable.
  • Keep TUI rendering/event handling separate from plan persistence. Refresh after writes and surface update events where available; do not rely on polling as the only consistency mechanism.
  • CLI output must not depend on TUI state, terminal capabilities, or an active interactive session.
  • Follow existing config/schema and command-registration patterns; no new config is required for basic management.
  • Define behavior for corrupt/unreadable plans, stale session plans, missing storage, concurrent deletion, and unsupported operations before implementation.

Phased delivery

  1. Host contract and read-only discovery: model/errors, list/get, status/version metadata, TUI browser, and CLI list/get with JSON.
  2. Safe mutations: create/update/status/export/delete/archive, TUI actions, CLI flags, expected-version conflicts, confirmations, and end-to-end storage tests.
  3. Session-plan integration: show the active session plan, connect exit_plan_mode/plan-updated events to host state, and make shared versus session scope explicit.
  4. Polish and adoption: accessibility/keyboard review, documentation/examples, telemetry or diagnostics if justified, and rollout behind an opt-in flag only if compatibility findings require it.

Acceptance criteria

  • A user can discover and open existing shared plans from the TUI without inspecting the data directory or invoking an agent tool.
  • TUI list/detail views show plan identity, scope, status, version/revision, and last-update information; long content is safely truncated or paginated.
  • TUI supports the agreed create/edit/status/export/delete-or-archive actions with confirmation for destructive actions.
  • The CLI provides list/get and all delivered mutating operations with documented human output and stable --json output.
  • Shared and session plans are clearly distinguished, and unsupported cross-scope operations fail with an actionable error.
  • Concurrent updates using a stale expected version fail deterministically, preserve the newer content, and report the current version; no silent overwrite occurs.
  • Not-found, corrupt/unreadable, storage, validation, and conflict errors are distinct in the host contract and covered by tests.
  • TUI and CLI tests cover empty lists, long content, invalid names/statuses, delete confirmation, refresh-after-write, and headless/non-TTY execution.
  • Existing plan toolset behavior and existing storage backends remain backward compatible; historical shared-plan and session-plan tests continue to pass.
  • Documentation includes examples for interactive and scripted workflows and explicitly links this feature to the historical work above.

Risks and rollout

  • Duplicate abstractions: a host-only store could diverge from agent tools. Mitigate by reusing the existing interfaces and adding contract tests shared by TUI/CLI.
  • Accidental destructive edits: require confirmations, show scope/version, and default to safe non-destructive actions.
  • Concurrent writers: enforce expected-version checks and provide refresh/retry UX.
  • Scope confusion: label shared versus session plans in every relevant view and command.
  • Storage/backend differences: capability detection and precise errors are preferable to pretending every backend supports every operation.
  • Breaking scripts: introduce the CLI incrementally, document JSON schema/versioning, and avoid changing existing tool output. Roll out read-only discovery first, then mutations, with an opt-in flag only if needed.

Decisions and open questions before implementation

  1. What exact CLI namespace and command names fit the existing docker agent command taxonomy?
  2. Is /plans the right TUI entry point, and how should it coexist with any existing plan/session slash commands?
  3. Should delete be permanent, or should the host UX use archive/restore while retaining the existing delete tool semantics?
  4. What is the canonical identity for a session plan, and which session-plan operations are safe to expose after the session ends?
  5. Which storage capabilities are mandatory for phase 1, and how should remote/custom backends advertise unsupported operations?
  6. Is status validation intentionally completely free-form, or should the host provide suggestions without enforcing an enum?
  7. What JSON schema/versioning and exit-code contract should scripts rely on?
  8. Which plan-updated/conflict events already exist, and what event payload is needed for a live TUI refresh?
  9. Should plan content editing be an embedded TUI editor, an external $EDITOR, or both?
  10. Are any operations permitted while a plan is actively being written by an agent, and how is that state represented?
  11. Which accessibility, color, and keyboard-navigation requirements are mandatory for the browser/editor?
  12. Do we need a feature flag for the first release, or can read-only host management ship directly while mutations follow in later phases?

Metadata

Metadata

Assignees

Labels

area/cliCLI commands, flags, output formattingarea/sessionsFor features/issues/fixes related to session lifecycle (resume, persistence, export)area/toolsFor features/issues/fixes related to the usage of built-in and MCP toolsarea/tuiFor features/issues/fixes related to the TUI

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions