# v0.3.0 Editorial Core Plan Status: shipped as part of the consolidated `v0.4.0` release on 2026-07-21 after Ghost 5 and Ghost 6 integration passed. ## Author support Add read-only `list_authors` with bounded search, pagination, and a maximum limit of 50, returning only `id`, `name`, `slug`, public URL, and post count. Never expose staff email, roles, permissions, status, or notification settings. Include ordered `{id, name, slug}` author objects in `list_posts` and `get_post`. Draft creation and update gain `authors?: string[]`. Every value must be an exact ID returned by `list_authors`: a positive decimal legacy staff ID (including the Ghost 5 owner ID `1`) or a 24-character ObjectID. Arrays contain 1–10 unique entries, supplied order is retained so the first author remains primary, and optimistic locking remains mandatory. Empty author arrays are rejected. Published attribution changes remain deferred because they immediately change public content. ## Bounded discovery Extend `list_posts` with `author_id`, `updated_after`, `updated_before`, `published_after`, `published_before`, and an explicit order enum containing only ascending or descending `updated_at` and `published_at`. Dates require RFC 3339 offsets and inverted ranges fail validation. Default order remains `updated_at desc`. Map these fields to fixed Ghost filters, including `authors.id` for the author ID. Retain the existing status, tag, title search, page, and limit inputs. Never expose arbitrary NQL, arbitrary field names, raw filter strings, or unbounded local search. ## Scheduling Add `schedule_posts` and `unschedule_posts`, both requiring caller-attested `user_confirmed: true`. `schedule_posts` accepts: ```ts { posts: Array<{ id: string; updated_at: string; published_at: string }>; user_confirmed: true; } ``` The batch contains 1–25 unique IDs; timestamps must be RFC 3339 with an offset; publication must be in the future. Preflight the complete batch before writing, accept only current drafts, then set `status: scheduled` with the exact instant. Never send newsletter parameters or trigger deployment. `unschedule_posts` accepts `{posts: Array<{id, updated_at}>, user_confirmed: true}` for exact scheduled posts, preflights the full batch, and returns them to draft. It neither deploys nor sends a newsletter. Static/headless operators must configure a Ghost `post.published` webhook so the future publication triggers their build. The local stdio server will not run a background scheduler. ## Complete patch semantics Draft patches allow `null` for excerpt, feature image, alt/caption, canonical, SEO, Open Graph, and Twitter fields. Empty tag arrays clear assignments; empty author arrays remain invalid. Title and Markdown remain non-null; timestamp collision protection remains mandatory. Published metadata patches gain `feature_image_url?: string | null`. The update still saves a Ghost revision, preserves `published` status, and excludes body, slug, tags, authors, status, newsletters, and scheduling fields. ## Acceptance criteria - Author reads omit all sensitive staff fields. - Draft create/update preserve ordered author IDs. - Bounded author/date/order filters produce only fixed NQL and reject malformed ranges. - Stale author and metadata updates make no write. - Every nullable field passes `null` to Ghost. - Published feature images can be replaced and cleared without changing body or status. - Scheduling rejects duplicate, stale, non-draft, malformed, or past targets before the first write. - Scheduling and unscheduling never deploy or send newsletters. - Ghost 5/6 integration assigns the integration owner, schedules a draft, reads scheduled state, unschedules it, and cleans it up. - Normal mode advertises fifteen tools; read-only mode advertises six, including `list_authors`. ## Headless limitations Scheduling changes Ghost state only. It cannot guarantee that a separate static site rebuilt at publication time. Documentation must distinguish Ghost scheduling success from public-site visibility and require an operator-owned webhook for headless deployments.