# Draft Piece

# Draft Piece (starter blueprint)

> **Slug:** `draft-piece`
> **Type:** `agent_blueprint`
> **Source:** code-defined; appears in every tenant's `agent_blueprint://list` automatically. Fork via `agents.fork_blueprint` to customize.
> **Outputs:** the new draft version number on the piece + the count of `content_grounding` children attached.

The single-piece drafter. Loads a `content_piece`, chases its FK references to pull author + voice + pillar, gathers substrate grounding evidence, writes the draft inline via prompt-fragment composition, attaches citation children, and writes the new draft as a new version on the piece. Drafts live as versions on the piece rather than as separate draft records.

## When to use it

- A user wants the AI to produce a full draft for a `content_piece` placeholder created by `plan_and_draft_window` (which inlines the planner) or by `artifacts.create` directly.
- You want a single-shot LinkedIn post / blog draft / newsletter section grounded in your voice + pillar + substrate evidence.
- You're invoking it as a sub-blueprint from `plan_and_draft_window` to back-fill drafts after the planner lands.

## Reading this blueprint

Per the agent blueprint substrate contract: this is a **recipe** the calling LLM reads and walks step-by-step. On the MCP tool surface (this surface) there is no one-shot run-blueprint tool: the calling LLM IS the runner — read the recipe and walk it. Each step description below is written as an instruction you can act on directly via the named primitives. (A separate headless SDK runner can also drive this blueprint to completion unattended — manual "Run now" (REST), schedule/event/webhook triggers, replay, and backtest sweeps; see `docs/blueprint-runner-sdk.md`. You cannot one-shot-run a blueprint from this MCP surface, but you CAN register an unattended run from it via the `blueprints` tool's `create_schedule`.)

## Validators that travel with content_piece writes (2026-05-12 relaxation)

Two registry validators run on every content_piece write — knowing them shapes how this blueprint works:

1. **`draftBodyRequired`** — pieces in status `drafting | ready | published` must carry a non-empty `content_json.draft_markdown`. Placeholder + archived are exempt. This blueprint's terminal `update_piece` step writes the body in the SAME patch as the status bump, so the rule is satisfied structurally; there is no intermediate state where the piece exists in drafting status with an empty body.

2. **`calendarPlanGate` (OPT-IN)** — gates `drafting | ready | published` transitions on an approved `content_calendar_plan` parent, but ONLY when the piece carries `content_json.metadata.requires_approval_gate = true`. Default behavior (flag missing or false): pass-through. This blueprint never opts in; agent-driven / ad-hoc drafting is the default path. Editorial flows that want batch approval should fork this starter and add the flag to the `update_piece` step's metadata.

## What it produces

The blueprint writes a new version of the supplied `content_piece` artifact with:

- `content_json.draft_markdown` — the full body in markdown.
- `content_json.status` — bumped to `'drafting'`.
- `metadata.auto_generated` — `true`.
- `metadata.review_status` — `'pending_review'`.
- `metadata.variant_key` — set to the input `variant_key` if supplied.

It also attaches one or more `content_grounding` children to the piece (`parent_artifact_id = piece_id`). Each citation child carries:

```jsonc
{
  "schema_version": "1.0.0",
  "quote": "<the quoted line>",
  "speaker": "<who said it>",
  "company": "<company name or null>",
  "source": "<conversation id / cluster id>",
}
```

The Calendar page detail panel renders citations beneath the draft body so the reader can see what the AI grounded each claim against.

## Inputs

| Name          | Type                        | Required | Description                                                                                                                           |
| ------------- | --------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `piece_id`    | artifact_ref(content_piece) | yes      | The piece to draft. Must already exist; create via `plan_and_draft_window` (which inlines the planner) or `artifacts.create`.         |
| `variant_key` | string                      | no       | Optional variant key tagged on the new draft version. Useful for producing multiple variants of the same piece (long, short, punchy). |

## How it runs

8 top-level steps:

1. **load_piece** — `tool`. `read_resource artifact://<piece_id>`. The read returns an envelope with `references` resolved so `pillar_id` and `author_id` arrive as `{ id, title, artifact_type, status }` envelopes alongside the raw uuids.
2. **load_author** — `tool`. `read_resource author_profile://<piece.author_id>`. The author profile carries `voice_profile_id`.
3. **load_voice** — `tool`. `read_resource voice_profile://<author.voice_profile_id>`. The voice rules embed into the draft prompt so the body matches workspace voice.
4. **gather_evidence** — `tool`. `data.cluster_search` keyed on `piece.content_json.topic`. Returns conversation themes the draft can quote and cite.
5. **assert_evidence** — `assert`. Halts with `evidence_missing` pause when zero clusters returned. The calling LLM surfaces a confirm pause: proceed without grounding (mark draft `metadata.grounding_status='ungrounded'`) or pause until the substrate has data.
6. **write_draft** — `llm`. Authors the draft body inline. Composes `prompt://content_writer/grounding_rules`, `audience_scoping`, `channel_budget`, `cta_synthesis`, `hook_patterns`. Outputs `draft_markdown` plus a citations array.
7. **attach_citations** — `loop`. Per cited evidence chunk, attaches a `content_grounding` child to the piece via `artifacts.create_child`.
8. **update_piece** — `tool`. `artifacts.update` writes the new draft body into `content_json.draft_markdown`. The update appends a new version row in `platform_artifact_versions` and bumps `current_version` automatically.

## Pause types and resume contract

| Pause type         | Triggered by                           | Resume requires                                              |
| ------------------ | -------------------------------------- | ------------------------------------------------------------ |
| `evidence_missing` | `assert_evidence` step (zero clusters) | confirm action: continue (proceed without grounding) or stop |

When `evidence_missing` fires, the chat panel offers two buttons: "Proceed without grounding" (resumes with `action='continue'`; the resulting draft is marked `metadata.grounding_status='ungrounded'` so reviewers know it's an opinion piece) and "Pause until data ingestion catches up" (resumes with `action='stop'` to abort).

## Reading and walking it

There is no run tool — read the recipe and walk its steps yourself. Via MCP from an external Claude Desktop:

```
read_resource agent_blueprint://draft-piece
```

Then gather the inputs (`piece_id: '5b2a...8e1d'`, `variant_key: 'long'`) and perform each step with your own primitive tools. For variant production: walk the recipe once per variant key with the same `piece_id` and a different `variant_key`. Each walk appends a new version, so the piece's version history is the variant history.

## Forking it

```
agents.fork_blueprint source=draft-piece new_slug=<your-fork>
```

Common forks:

- **Channel-specific drafting** — fork to a Twitter-only or LinkedIn-only variant with hardcoded channel + tighter word budgets.
- **Skip research by default** — drop `gather_evidence` and `assert_evidence` for opinion-heavy publishing.
- **Custom evidence layer** — extend `gather_evidence` to call your CRM tool, intercom search, or other tenant-specific source before the synthesis step.
- **Multi-source citations** — replace the single `data.cluster_search` with a parallel fan-out to substrate + KB + a custom index, then merge before the draft step.

## Limits

- Reads are not cost-bounded server-side in v1.
- The piece, author, and voice references all resolve within the calling API key's workspace; cross-tenant references fail at the operation registry boundary.
- The drafter expects the piece to already have `pillar_id` and `author_id` populated (placeholder pieces created by `plan_and_draft_window`'s inlined planner always do; pieces created manually via `artifacts.create` may not — the blueprint will halt at `load_author` if `author_id` is null).
- Each invocation produces ONE draft. For variant generation, run the blueprint multiple times with different `variant_key` inputs.
