Bound deck display

July 3, 2026 · View on GitHub

One-liner: Cursor and Claude Code users always see which Agent Deck is bound to the current workspace — in the prompt status line — without opening the dashboard or parsing MCP JSON.

Status: Phase 5a shipped · Codegen load path: docs/PRD_DECK_DISPLAY.md · Contracts: packages/shared/src/schemas/deck-display.ts (Zod + exported JSON Schema)


1. Product overview

Agent Deck scopes MCP tools via a bound deck (session bind_workspace, env, or header). The agent harness teaches agents to call bind_workspace but exposes no human-visible indicator of which deck is active. Users report uncertainty after switch_bound_deck or when multiple decks share similar MCP sets.

This PRD specifies a live MCP display registry, a agent-deck statusline CLI integrated with Cursor/Claude status lines, a display API, and minimal MCP/harness additions. Session binding remains in-memory (McpSessionBindingStore); the backend registry bridges live MCP binds to the terminal footer.

Success criteria (time-boxed):

#CriterionTarget window
SC-1Status line shows correct deck name within one prompt update after bind_workspacePhase 5a
SC-2switch_bound_deck updates status line for this session onlyPhase 5a
SC-3Unbound until bind_workspace({ deckId }); no repo file auto-bindPhase 5a
SC-4No secret values in sidecar, status line, or summary resourcePhase 5a
SC-5agent-deck setup --statusline installs config idempotentlyPhase 5b — shipped

2. Target users & roles

PersonaGoalv1 surface
Cursor / Claude Code userGlance at prompt footer for active deckStatus line via agent-deck statusline
Solo devConfirm bind workedSidecar + status line
Monorepo devCorrect deck when cwd is a package subfolderWorkspace walk-up (MONOREPO_SCOPE.md)
Agent (MCP)One-line deck summaryget_session_binding.display_summary
Power userDebug wrong deckagent-deck statusline --workspace <path>

Voice: Cold-reader. Distinguish editing deck (dashboard localStorage) from bound/effective deck (agent scope) — only the latter appears in the status line.


3. User stories (testable)

US-1 — See deck after bind

As a Cursor user I want the status line to show my deck name after bind_workspace so that I know scoping succeeded.

Acceptance:

  • After successful bind_workspace, status line within 300 ms (next host refresh) shows ◆ <deckName> · <counts>
  • Live display registry updated on backend (in-memory, per MCP session)
  • No deck name written to agent-deck.mdc / CLAUDE.md

v1 · Phase 5a

US-2 — Session deck override visible

As a user who called switch_bound_deck I want the status line to reflect the override so that I know only this session changed decks.

Acceptance:

  • Status line shows new deck name after switch_bound_deck
  • source: session_override reflected in API GET /api/scope/display (optional suffix in line)

v1 · Phase 5a

US-3 — Unbound before bind

As a user at session launch I want the status line to show unbound so that I am not misled by stale manifest or sidecar data.

Acceptance:

  • agent-deck statusline with cwd in repo shows ◆ Unbound — bind a deck to use Agent Deck until bind_workspace({ deckId })
  • Leftover .agent-deck/deck.yaml files do not populate the footer

v1 · Phase 5a (reality-only model)

US-4 — Agent Deck offline

As a user when the backend is stopped I want a non-breaking status line so that my prompt still works.

Acceptance:

  • Status line prints ◆ Agent Deck offline or empty string (configurable); exit 0
  • No hang beyond timeoutMs (default 1500 ms)

v1 · Phase 5a

US-5 — One-shot setup

As a new user I want agent-deck setup --statusline so that I do not hand-edit cli-config.json.

Acceptance:

  • Merges statusLine.command: agent-deck statusline into ~/.cursor/cli-config.json
  • Re-run is no-op when already current
  • Documented for Claude Code equivalent

Deferred · Phase 5b

US-6 — Dashboard sessions panel

As a debugger I want to see live MCP session binds (with badges) so that I can correlate chats with menu bar rows and spot stale binds.

Acceptance:

  • GET /api/scope/bindings lists live session rows (badge, deck, workspace, activity)
  • Page header (top-right) shows live session count (⌘N); click opens all badges grouped by workspace
  • Full dedicated sessions sidebar (optional P1 — out of initial badge chip scope)

Shipped · Phase 5c (badge chip on Deck panel)


4. Features & requirements

Pillar A — Live MCP display registry

Req IDRequirementAcceptance
F1.1On bind_workspace / switch_bound_deck success, MCP POSTs to POST /api/scope/live-displayAgent client header required
F1.2Registry keyed by MCP session id; lookup by workspace walks up monorepo parentsIn-memory on backend
F1.3Entry includes deckId, deckName, source, updatedAt, cardCountsNo secrets
F1.4MCP session close DELETEs registry rowFooter clears on disconnect

Pillar B — Display resolution

Req IDRequirementAcceptance
F2.1Precedence: live MCP bind for workspace → unboundNo sidecar, env, or manifest guessing
F2.2GET /api/scope/display?workspaceRoot= returns DeckDisplay (§7.2)Used by statusline
F2.3Monorepo walk-up for live registry lookupSame walk-up as former sidecar
F2.4Unbound returns deckName: null; status line shows ◆ Unbound — bind a deck to use Agent DeckUS-4

Pillar C — Status line CLI

Req IDRequirementAcceptance
F3.1agent-deck statusline reads JSON stdin (StatusLinePayload)Uses cwd / workspace.project_dir for workspace lookup
F3.2agent-deck statusline --workspace <path> for debugNo stdin required
F3.3Output format: ◆ {name} · {counts} (updated YYYY-MM-DD HH:mm) when boundMax 120 chars; truncate name
F3.4Respects AGENT_DECK_PORT / CLI defaults for API URLWorks in dev and prod
F3.5Exit 0 always unless misconfigurationNever blocks host
F3.6No timer polling in setup — host refreshes on prompt/conversation update onlyClaude: omit refreshInterval; Cursor: omit updateIntervalMs

Pillar D — MCP & harness

Req IDRequirementAcceptance
F4.1get_session_binding adds display_summary stringSame format as F3.3
F4.2Resource agent-deck://bound-deck/summary plain textmime text/plain
F4.3Harness adds one static line: user may see deck in status line; do not repeat each turnpackages/cli/src/agent-harness.ts
F4.4Do not inject dynamic deck into harness filesCode review gate

Pillar E — Setup

Req IDRequirementAcceptance
F5.1setup --statusline merges Cursor cli-configIdempotent
F5.2Document Claude Code status line in SETUP.mdLink to Claude docs

5. Pricing model

Skipped — display feature; no billing.


6. Design principles

PrincipleRequirement
Fail softF3.5, US-4
No secrets in UIF1.3, SC-4
Static harnessF4.4
Workspace-nativeHost already knows cwd; no new host APIs for P0

7. Cross-cutting contracts

JSON Schema Draft 2020-12. Implementation: packages/shared/src/schemas/deck-display.ts.

7.1 Live display registration (POST /api/scope/live-display)

Agent client only. Body fields: mcpSessionId, workspaceRoot, deckId, deckName, source, cardCounts, updatedAt. Removed on MCP session close via DELETE /api/scope/live-display/:mcpSessionId.

7.2 Deck display API (DeckDisplay)

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://agent-deck.dev/schemas/deck-display/v1.json",
  "type": "object",
  "required": ["workspaceRoot", "deckId", "deckName", "source", "cardCounts", "agentDeckOnline"],
  "properties": {
    "workspaceRoot": { "type": "string" },
    "deckId": { "type": ["string", "null"], "format": "uuid" },
    "deckName": { "type": ["string", "null"] },
    "source": {
      "enum": ["session_override", "env", "unbound"]
    },
    "cardCounts": {
      "type": "object",
      "properties": {
        "mcp": { "type": "integer" },
        "credentials": { "type": "integer" },
        "playbooks": { "type": "integer" }
      }
    },
    "oauthWarningCount": { "type": "integer" },
    "agentDeckOnline": { "type": "boolean" },
    "mcpOnline": { "type": "boolean" },
    "updatedAt": { "type": "string", "format": "date-time" },
    "displayLine": {
      "type": "string",
      "description": "Pre-rendered status line per F3.3"
    }
  }
}

7.3 Status line stdin (StatusLinePayload subset)

FieldTypeRequiredUse
cwdstringyesResolve workspace for live registry lookup
workspace.current_dirstringnoFallback if cwd absent
workspace.project_dirstringnoPreferred workspace root when set
session_idstringnoIgnored (host id ≠ MCP session id)

Agent Deck ignores model, tokens, and other payload fields.

Status line contract: Footer shows live MCP bind only. bind_workspace / switch_bound_deck register on the backend; unbound until bind. No bindings.json sidecar.


8. Technical constraints & preferences

ConstraintDetail
As-builtMcpSessionBindingStore in-memory only (packages/backend/src/mcp-session-binding.ts)
MCP toolsbind_workspace, switch_bound_deck, get_session_binding (packages/backend/src/mcp-server.ts)
HarnessStatic agent-deck.mdc / CLAUDE.md markers (AGENT_HARNESS.md)
Cursor status line~/.cursor/cli-config.json statusLine.type: command
Codegen entrypackages/cli/src/statusline.ts + backend route GET /api/scope/display

Example Cursor config:

{
  "statusLine": {
    "type": "command",
    "command": "agent-deck statusline",
    "padding": 2,
    "timeoutMs": 1500
  }
}

9. Non-functional requirements

NFRTargetMeasurement
NFR-1 Statusline cold latencyp95 < 300 msagent-deck statusline with running backend; n ≥ 50
NFR-2 Statusline offline latencyp95 < 100 msBackend stopped; fail fast
NFR-3 Sidecar writeNon-blocking on MCP bind pathp95 < 10 ms added to bind tool
NFR-4 Display line length≤ 120 charactersUnit test
NFR-5 Secret leakage0 secret fields in sidecar/displayStatic analysis + test

10. Out of scope

ItemRationale
Cursor/Claude IDE Agent chat panelNo host API; deferred — terminal statusline only
Dynamic harness / per-bind rule rewritesBreaks setup idempotency (F4.4)
Global single-deck indicator across all reposConflicts with workspace bind model
Dashboard live mirror of every Cursor windowUS-6 optional P1 only
Showing editing deck in status lineDifferent concept from bound deck
Claude Desktop status lineUnknown support; document MCP fallback

11. Milestones

WeekExit criteria
5aSidecar F1.; API F2.; CLI F3.*; MCP F4.1–F4.2; SC-1–SC-4
5bSetup F5.*; harness F4.3; SC-5
5cDashboard bindings panel US-6; oauth warning suffix (OD-1)

12. Open decisions

QuestionDefault if undecidedOwner
OD-1 Show OAuth warning count in status line (· 1 reconnect)?No in 5a; add in 5c if room under 120 charsProduct
OD-2 Claude Desktop status line support?Document get_session_binding onlyDocs
OD-3 Cursor Chat (non-CLI) deck badge?Defer; out of scope §10Product

13. How to use this PRD

ConsumerDirective
EngineerLand 5a (sidecar + statusline + API) before setup UX. Wire sidecar write in MCP bind handlers first.
AI codegenImplement §7 schemas, then statusline.ts, then MCP display_summary, then setup flag.
UserRun agent-deck setup --client cursor --statusline after upgrading to build with 5b.
AgentUse display_summary from get_session_binding; do not spam deck name if user sees status line (F4.3).

Appendix — source notes

SourceCaptured as
Agent Deck playbook pb_ai_codegen_prd on dev deckDocument structure
Agent Deck playbook pb_product_principleVoice, editing vs bound deck distinction
User request — display deck in Cursor/Claude§1 problem
MVP.md Module 1 bind precedenceF2.1
AGENT_HARNESS.mdF4.3, §10 harness
packages/backend/src/mcp-session-binding.ts§8 in-memory gap
Cursor status line skill / Claude statusline docs§8 config

Codegen-readiness checklist

  • One-sentence value statement at top
  • Every user story has verifiable acceptance checkboxes
  • Every requirement has stable Req ID
  • Cross-boundary shapes are JSON Schema (§7)
  • NFR table has measurement window + sample size
  • Out of scope in exactly one section (§10)
  • Open decisions have Default if undecided (§12)
  • Codegen load path + contracts directory named (§8)
  • Statusline stdin subset committed (§7.3)
  • Pricing section skipped (§5)