--- name: calendar-schedule description: > Turn a content plan — often produced by the social-calendar or social-repurpose skills — into real scheduled posts on the real calendar: parse the plan, map every row to a connected channel, preview each row's server-side readiness, propose the full week's schedule, and book every row with one call each. Covers LinkedIn, X (Twitter), Instagram, and Facebook today, with Mastodon, Threads, Bluesky, TikTok, and YouTube in platform review. Use when the user says "schedule my week", "schedule this plan", "put my calendar on the calendar", or "schedule these posts". Requires the Inklate CLI (npm i -g inklate) or the Inklate MCP connection. Reads social-context.md when present for cadence and voice. The receipt is the week as a table of real scheduled times and post IDs, verified against the queue. license: MIT metadata: version: 0.2.0 topics: - planning - publishing examplePrompt: "Schedule this two-week content plan across my channels" pairsWith: - social-calendar - social-repurpose mcpTools: - posts_create - posts_validate - posts_list - posts_get cliCommands: - posts create - posts validate - posts list - posts get --- Take a content plan off the page and onto the real calendar: every row becomes one validated, scheduled post with a confirmed time on a real channel. ## Transports - **CLI (preferred):** `inklate` (`npm i -g inklate`) — structured YAML on stdout (`--json` for JSON), progress on stderr, and typed exit codes: `3` no credentials, `4` a deliberate refusal — arming a row that isn't `ready` — with its machine-readable payload on stdout, `5` not found, `6` the resource changed underneath you, `7` rate limited but safe to re-run later. Pass `--no-input` when running unattended so a missing flag fails loudly instead of prompting, and `--yes` to carry an approval the user has already given in chat. - **MCP (fallback):** the Inklate MCP tools when the CLI is not installed. Steps below name the MCP operation with the CLI form in parentheses; the fields are the same on both. ## Connection check 1. Run `inklate auth check` (MCP: `organizations_list`) first. 2. On exit 3 (no credentials): interactively run `inklate auth login`; headless, the key comes from `INKLATE_API_KEY=inklate_…` in the environment or `inklate auth set --token inklate_…`. If neither transport is available at all, tell the user to install with `npm i -g inklate` (or connect at `https://inklate.com/skills/connect?ref=skills-calendar-schedule`) and STOP. 3. If multiple organizations exist, ask which one owns this calendar. All times and channels below are scoped to that organization (CLI: `--org `). ## Context Read `social-context.md` (project root, then `.agents/social-context.md`) if present. `## Cadence` is the reality check against overstuffed plans, `## Platforms` resolves ambiguous channel names in the plan, and `## Voice` / `## Never` govern any content adjustments you make while resolving errors. Proceed without it if absent. ## Workflow 1. **Parse the plan.** Read the plan table or list the user provides. Extract per row: content (or a pointer to a draft), target channel(s), and intended day/time. Flag rows you cannot parse instead of guessing. 2. **Map rows to channels.** Match each row's platform to a connected channel. Rows targeting unconnected platforms get flagged and set aside — never silently dropped, never scheduled to a wrong channel. 3. **Preview every row before booking anything.** Call `posts_validate` (CLI: `inklate posts validate --content … --channel …`) for each mapped row — a dry run, nothing is stored. Read each row's `ready` and per-channel `errors[]`/`warnings[]`. For every fixable error, adjust the row's content directly (autofix already applied where it could when you actually create it, but a dry-run preview surfaces judgment calls early); surface judgment calls to the user in one consolidated batch, not one interruption per row. 4. **Build the proposed schedule.** Convert the plan's intended times into concrete datetimes in the organization's timezone, then apply the constraints: - Spacing: no two posts on the same channel within 3 hours — when the plan violates this, nudge the later post and note the nudge. - Existing queue: check `posts_list` (CLI: `inklate posts list --scheduled-from … --scheduled-to …`) for already-scheduled posts in the window so the new week doesn't collide with them. - Rows with a day but no time get a sensible default for that platform, marked as your suggestion. - Past times are an error, not a nudge: flag any row whose intended time has already passed. 5. **Approval gate.** Present the entire proposed week as one table — day, time (org timezone), channel, content summary, readiness from step 3 — before anything is booked. Scheduling posts is a real-world action: get an explicit yes on the whole table, or apply the user's edits and re-present. Never book a partial week on an implicit go-ahead. 6. **Book it — one call per row.** On approval, call `posts_create` (CLI: `inklate posts create --content … --channel … --scheduled-at