Proposal Skill
This skill covers the Planning stage of the AI-DLC workflow: creating Proposals that contain document drafts (PRD, tech design) and task drafts with dependency DAGs, then submitting them for Admin review.
Tool namespace: Chorus tools are exposed by the connected MCP server under a
mcp__chorus__prefix on dsh (e.g.mcp__chorus__chorus_pm_create_proposal). Bare names are used below for readability — prependmcp__chorus__when invoking. Seechorusfor the full rule.
Overview
After an Idea's elaboration is resolved (see idea-chorus), the PM Agent creates a Proposal — a container that holds document drafts and task drafts. On Admin approval, these drafts materialize into real Documents and Tasks.
Elaboration resolved --> Create Proposal --> Add drafts --> Validate --> Submit --> Reviewer --> Admin /review
Tools
Proposal Management:
| Tool | Purpose |
|---|---|
chorus_pm_create_proposal |
Create empty proposal container |
chorus_pm_validate_proposal |
Validate proposal completeness (returns errors, warnings, info) |
chorus_pm_submit_proposal |
Submit proposal for Admin approval (draft -> pending) |
Document Drafts:
| Tool | Purpose |
|---|---|
chorus_pm_add_document_draft |
Add document draft to proposal |
chorus_pm_update_document_draft |
Update document draft content |
chorus_pm_remove_document_draft |
Remove document draft from proposal |
Task Drafts:
| Tool | Purpose |
|---|---|
chorus_pm_add_task_draft |
Add task draft (returns draftUuid for dependency chaining) |
chorus_pm_update_task_draft |
Update task draft |
chorus_pm_remove_task_draft |
Remove task draft from proposal |
Post-Approval (tasks exist):
| Tool | Purpose |
|---|---|
chorus_create_tasks |
Batch create tasks (supports intra-batch dependencies via draftUuid) |
chorus_pm_assign_task |
Assign a task to a Developer Agent |
chorus_pm_create_document |
Create standalone document |
chorus_pm_update_document |
Update document content (increments version) |
chorus_update_task (with addDependsOn / removeDependsOn) |
Add or remove task dependencies (with cycle detection) |
Shared tools (checkin, query, comment, search, notifications): see chorus
Workflow
Step 1: Create an Empty Proposal
Recommended approach: Create the proposal container first without any drafts, then incrementally add document and task drafts one by one.
Resolve the spec mode BEFORE you create the container (Step 1.5). The container
descriptionmust carry the resolved mode's locator line (OpenSpec:OpenSpec change slug: <slug>; spec-lite:Spec-lite: .chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/; free-form: none), anddescriptionis only settable at creation time. So read the## Spec Modeblock and decide the slug / dated path first, then create the container with the right line already in place.
chorus_pm_create_proposal({
projectUuid: "<project-uuid>",
title: "Implement <feature name>",
description: "Analysis and implementation plan for Idea #xxx",
inputType: "idea",
inputUuids: ["<idea-uuid>"]
})
Multiple Ideas: You can combine multiple ideas into one proposal by passing multiple UUIDs in inputUuids.
A theme cannot be a proposal input —
chorus_pm_create_proposalrejects any input idea withisContainer = true. Derive a child idea from the theme and write the proposal on the child instead. (See the theme-ideas section of theidea-chorusskill.)
Step 1.5: Select spec mode
The chorus-dsh bundle resolves one spec mode at plugin load and injects a ## Spec Mode block into your first-step context stating CHORUS_SPEC_MODE=<lite|openspec|off> + a routing note (it also publishes CHORUS_SPEC_MODE / CHORUS_OPENSPEC_ACTIVE to the environment). Consume that value — do NOT re-derive it. Resolve the mode here, before creating the container (Step 1), so the description carries the right locator line.
dsh note: there is no Claude Code SessionStart hook, but the bundle precomputes the mode the same way. Read the
## Spec Modeblock (or theCHORUS_SPEC_MODE/CHORUS_OPENSPEC_ACTIVEenv vars) — seeopenspec-aware-chorus§1. Only if that context is genuinely absent, resolve the full mode (never hand-roll an OpenSpec-only check that ignoresCHORUS_SPEC_MODE).
Branch on the resolved mode (three branches):
OpenSpec (
CHORUS_OPENSPEC_ACTIVE=1line present) → load theopenspec-aware-chorusskill and follow its §3. Pick$SLUG, scaffoldopenspec/changes/<slug>/, authorproposal.md/design.md/specs/<capability>/spec.mdlocally, create the container (Step 1) with the literal lineOpenSpec change slug: <slug>indescription, and mirror each local file into a document draft.⛔ Mandatory in OpenSpec mode: mirror calls fill
contentfrom the local file — preferchorus mcp call … --arg-file content=<file>, falling back to the package-localCHORUS_MCP_CALLwrapper withjson_encode_filewhenchorusis not onPATH— seeopenspec-aware-chorus§3.6. Do not callchorus_pm_add_document_draftdirectly from the MCP harness with a hand-typedcontentfield. Re-typing thousands of lines through the LLM burns 20k+ content tokens per proposal and breaks byte-equality with the local source of truth (openspec-aware-chorus§2 Rule 1). Skip Step 2 below in OpenSpec mode — the file-fill flow in §3.6 replaces it for documents.spec-lite (
CHORUS_SPEC_MODE=lite) → load thespec-lite-chorusskill and follow its flow. Pick$SLUG(a capability), ensure the durable.chorus/specs/<slug>/spec.mdexists and update it in place (local-only, no ids, never mirrored), create this change's dated folder.chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/with its Chorus-typed docs (prd.mdrequired;tech_design.md… optional), create the container (Step 1) with the literal lineSpec-lite: .chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/indescription, and mirror each dated-folder<type>.mdinto a document draft byte-exact (same--arg-filetransport as OpenSpec).spec.mdis never mirrored. Noopenspec/changes/scaffold, notasks.md. Skip Step 2's inline free-form authoring — the file-fill flow replaces it for documents.free-form (
CHORUS_SPEC_MODE=off) → proceed with Step 2 unchanged. Author drafts inline as free-form Markdown via direct MCPchorus_pm_add_document_draft. No.chorus/specs/oropenspec/changes/files.
If the
## Spec Modeblock says the mode cannot be honored (explicitCHORUS_SPEC_MODE=openspecbut OpenSpec is unusable), halt and surface it — do NOT silently fall back to spec-lite or free-form.
Step 2: Add Document Drafts
Add document drafts one at a time:
# Add PRD
chorus_pm_add_document_draft({
proposalUuid: "<proposal-uuid>",
type: "prd",
title: "PRD: <Feature Name>",
content: "# PRD: <Feature Name>\n\n## Background\n...\n## Requirements\n..."
})
# Add Tech Design
chorus_pm_add_document_draft({
proposalUuid: "<proposal-uuid>",
type: "tech_design",
title: "Tech Design: <Feature Name>",
content: "# Technical Design\n\n## Architecture\n...\n## Implementation\n..."
})
Document types: prd, tech_design, adr, spec, guide
Step 3: Add Task Drafts
Add task drafts one at a time. The response returns the new draft's draftUuid — use it directly for dependsOnDraftUuids in subsequent drafts.
acceptanceCriteriaItems is required — every task draft must include at least one item with a non-blank description, or the call is rejected. Use the structured acceptanceCriteriaItems array (the legacy acceptanceCriteria Markdown string does not satisfy the requirement).
# First task -> response includes { draftUuid, draftTitle }
chorus_pm_add_task_draft({
proposalUuid: "<proposal-uuid>",
title: "Implement <component>",
description: "Detailed description of what to build...",
priority: "high",
storyPoints: 3,
acceptanceCriteriaItems: [
{ description: "Criteria 1", required: true },
{ description: "Criteria 2", required: true }
]
})
# Second task — depends on first
chorus_pm_add_task_draft({
proposalUuid: "<proposal-uuid>",
title: "Write tests for <component>",
description: "Unit and integration tests...",
priority: "medium",
storyPoints: 2,
acceptanceCriteriaItems: [
{ description: "Test coverage > 80%", required: true }
],
dependsOnDraftUuids: ["<draftUuid-from-first-task>"]
})
To edit a draft's criteria later via
chorus_pm_update_task_draft, pass a non-emptyacceptanceCriteriaItemsto replace them; omit the field to leave them unchanged. The field cannot be used to clear criteria.
Task priority: low, medium, high
Step 4: Review and Refine Drafts
# Review current state. chorus_get_proposal defaults to section:"basic"
# (metadata + a lightweight draft index, no bodies). Use section:"full" to
# see every draft's content, or section:"documents"/"tasks" for one kind.
chorus_get_proposal({ proposalUuid: "<proposal-uuid>", section: "full" })
# Update a document draft
chorus_pm_update_document_draft({
proposalUuid: "<proposal-uuid>",
draftUuid: "<draft-uuid>",
content: "Updated content..."
})
# Update a task draft
chorus_pm_update_task_draft({
proposalUuid: "<proposal-uuid>",
draftUuid: "<draft-uuid>",
description: "Updated description...",
dependsOnDraftUuids: ["<other-draft-uuid>"]
})
# Remove a draft
chorus_pm_remove_task_draft({
proposalUuid: "<proposal-uuid>",
draftUuid: "<draft-uuid>"
})
Step 5: Validate and Submit
Before submitting, validate to preview issues:
chorus_pm_validate_proposal({ proposalUuid: "<proposal-uuid>" })
Returns { valid, issues } with error, warning, and info levels. Fix errors before submitting.
When validation passes:
chorus_pm_submit_proposal({ proposalUuid: "<proposal-uuid>" })
This changes the status from draft to pending. An Admin will review it (see review-chorus).
Add a comment explaining your reasoning:
chorus_add_comment({
targetType: "proposal",
targetUuid: "<proposal-uuid>",
content: "This proposal covers... Key decisions: ..."
})
Step 5.5: Run the Proposal Reviewer (inline — no hook on dsh)
dsh difference: the Claude Code plugin relies on a PostToolUse hook to inject a "spawn the reviewer" reminder after
chorus_pm_submit_proposal. dsh has no such hook. Run the reviewer step inline, right here, immediately after submitting. Do not wait for an injected reminder — it will never come.
Obtain an independent VERDICT before considering the proposal ready for Admin approval:
Preferred — spawn a reviewer sub-agent (foreground). Use the dsh
subagenttool to spawn a sub-agent withrun_in_background: false(foreground — the call waits for the reviewer to finish, and the verdict is theVERDICT:comment it posts rather than the call's return value; the approve/reject decision depends on the verdict) whose task tells it to call theskilltool withproposal-reviewer-chorus, then review the proposal. The authoritative result is this round'sVERDICT:comment on the proposal. Setrun_in_background: true(a continuable/background sub-agent whose settlement notice you collect later) only when you deliberately want to fan out and don't need the verdict before your next step.Load and run the proposal-reviewer-chorus skill to review proposalUuid <uuid>. Read the proposal, its documents, the idea, and the elaboration; classify findings BLOCKER/NOTE; post your VERDICT comment on the proposal when done.Fallback — review it yourself. If
subagentis unavailable on your host (spawning disabled by policy), perform the review yourself as a focused, read-only pass following theproposal-reviewer-chorusskill's procedure: readchorus_get_proposal,chorus_get_comments, the linked idea, and the elaboration; check document completeness, task granularity, AC ↔ requirement coverage, the dependency DAG, and integration checkpoints; then record the result yourself viachorus_add_commentending with aVERDICT:line (PASS / PASS WITH NOTES / FAIL). Do NOT modify any drafts during this pass — it is review-only. Use the same BLOCKER vs NOTE classification theproposal-reviewer-chorusskill defines.Read the VERDICT and act:
chorus_get_comments({ targetType: "proposal", targetUuid: "<proposal-uuid>" })Find THIS round's
VERDICT:comment — the one posted after your dispatch, not an older round's:- PASS / PASS WITH NOTES — proceed; an Admin can approve (notes are non-blocking).
- FAIL — go to Step 6 and fix the BLOCKERs before resubmitting.
If no new VERDICT: comment appears after the reviewer returns, check what it did post. A comment reporting that the round limit was reached, or any other explicit refusal to review, is a deliberate escalation to a human: STOP — do not respawn, do not self-review, do not post a VERDICT of your own. If it posted nothing at all, respawn it ONCE, telling it to stay within its turn budget and reserve its last turns for the VERDICT, then apply this same check again to what the retry posts. An explicit refusal from the retry still means STOP; only a second true silence lets you fall back to reviewing manually (Step 5.5 fallback) and post the VERDICT yourself. Absence is never a PASS.
Step 6: Handle Feedback
After the reviewer runs (or an Admin reviews), if the VERDICT is FAIL or the Admin rejects, you need to revise and resubmit.
IMPORTANT: A proposal in pending status cannot be edited. You must reject it first to return it to draft status before editing any drafts.
Read feedback:
chorus_get_proposal({ proposalUuid: "<proposal-uuid>", section: "full" }) chorus_get_comments({ targetType: "proposal", targetUuid: "<proposal-uuid>" })Identify BLOCKERs from the reviewer VERDICT or rejection note.
Reject the proposal (self-reject your own, or ask admin to reject someone else's):
chorus_pm_reject_proposal({ proposalUuid: "<proposal-uuid>", reviewNote: "Reviewer FAIL. Fixing BLOCKERs: <list>" })This returns the proposal to
draftstatus. PM agents can only reject their own proposals; admin agents can reject any proposal.Revise the drafts:
chorus_pm_update_document_draft({ proposalUuid: "<proposal-uuid>", draftUuid: "<uuid>", content: "..." }) chorus_pm_update_task_draft({ proposalUuid: "<proposal-uuid>", draftUuid: "<uuid>", ... })Resubmit and re-run the reviewer (Step 5 → Step 5.5 again):
chorus_pm_submit_proposal({ proposalUuid: "<proposal-uuid>" })
Step 7: Post-Approval
When the Admin approves:
- Document drafts become real Documents
- Task drafts become real Tasks (status:
open, ready for developers) - The Idea's displayed status is automatically derived from Proposal and Task progress -- no manual update needed
Step 8: Manage Task Dependencies (Optional)
After tasks are created, you can manage dependencies:
Batch create tasks with intra-batch dependencies:
chorus_create_tasks({
projectUuid: "<project-uuid>",
tasks: [
{ draftUuid: "draft-db", title: "Create database schema", priority: "high", storyPoints: 2 },
{ draftUuid: "draft-api", title: "Implement API endpoints", priority: "high", storyPoints: 4, dependsOnDraftUuids: ["draft-db"] },
{ title: "Write integration tests", priority: "medium", storyPoints: 2, dependsOnDraftUuids: ["draft-api"] }
]
})
Add/remove dependencies on existing tasks:
chorus_update_task({ taskUuid: "<task-B-uuid>", addDependsOn: ["<task-A-uuid>"] })
chorus_update_task({ taskUuid: "<task-B-uuid>", removeDependsOn: ["<task-A-uuid>"] })
Dependencies are validated: same project, no self-dependency, no cycles (DFS detection).
Step 9: Assign Tasks to Developer Agents (Optional)
chorus_pm_assign_task({ taskUuid: "<task-uuid>", agentUuid: "<developer-agent-uuid>" })
- Task must be
openorassigned - Target agent must have
task: ["write"]permission
Document Writing Guidelines
PRD Structure
# PRD: <Feature Name>
## Background
Why this feature is needed.
## Requirements
### Functional Requirements
- FR-1: ...
### Non-Functional Requirements
- NFR-1: ...
## User Stories
- As a <role>, I want <action>, so that <benefit>
## Out of Scope
What is NOT included.
Tech Design Structure
# Technical Design: <Feature Name>
## Overview
High-level approach.
## Architecture
System design, component interactions.
## Data Model
Schema changes, new tables.
## API Design
New/modified endpoints.
## Module Contracts
Shared conventions across tasks: return value format, error handling pattern, cross-module call points.
## Implementation Plan
Step-by-step implementation order.
## Risks & Mitigations
Potential issues and how to address them.
Task Writing Guidelines
Good tasks are:
- Module-scoped — One cohesive functional module per task, not a single function or file
- Testable — Clear, cohesive acceptance criteria are required on every task (at least one non-blank item; max 6; group related checks into one criterion but list key coverage, e.g. "All tests pass: service layer unit tests, API integration tests, edge case handling")
- Sized — 1-8 story points (hours of agent work)
- Ordered — Use
dependsOnDraftUuids/dependsOnTaskUuidsto express execution order - Descriptive — Include enough context for a developer agent to start without questions. For tasks with cross-module dependencies, reference the tech design's Module Contracts in the AC
- Integration checkpoints — For DAGs with 4+ tasks, include at least one integration checkpoint task at a convergence point whose AC requires end-to-end execution of preceding modules together
- Hallucination-aware — When tasks involve external dependencies, note in the task description that developers should verify specifics (API signatures, CLI flags, config keys, model IDs, etc.) against official docs rather than relying on LLM memory
Task Granularity
Each task should correspond to an independently runnable and testable functional module — not a single function, file, or API endpoint. Avoid splitting closely related functionality into separate tasks; the Chorus workflow overhead per task (claim → implement → self-test → submit → verify) adds up quickly.
Bad → Good examples:
- Bad:
Book Search+Book CRUD(2 tasks) → Good:Book Management(1 task covering CRUD + Search for the same entity) - Bad:
Chart Rendering+Statistics Calculation(2 tasks) → Good:Data Analytics(1 task covering stats + visualization as one module)
Tips
- Keep PRD focused on what and why; tech design focused on how
- Break large features into cohesive module-scoped tasks — but avoid over-splitting related functionality into too many tiny tasks
- Add
storyPointsto help prioritize and estimate effort - Keep acceptance criteria cohesive — group related verifications into one item rather than listing each check separately
- Always set up task dependency DAG — tasks without dependencies are assumed parallelizable
- When multiple tasks share data formats or call each other, define contracts in the tech design before writing task AC
- When combining multiple ideas, explain how they relate in the proposal description
- Always run the reviewer inline after submit (Step 5.5) — dsh has no hook to remind you
Next
- After submission, an Admin will review using
review-chorus - After approval, Developers claim tasks using
develop-chorus - For Idea elaboration, see
idea-chorus - For platform overview, see
chorus